Article
Introduction
This goal of this document is to show how Novell Access Manager can be used to single sign on to Google Apps using SAML2. Although we will be referencing SAML authentication requests and responses, and assertion specifics, details on the SAML protocol is outside the scope of this document. An outline of the configuration steps required on both the Novell Access Manager Identity server and Google Apps server will be covered. We will also cover some basic troubleshooting in a separate section where we look at available tools and log files for troubleshooting SAML, as well as sample entries showing successful communications.
Contents
- Installation Prerequisites
- High level overview of the SAML posting process
- Configuring Google Apps to integrate with Novell Access Manager
- Configuring Novell Access Manager to integrate Google Apps
- Troubleshooting
Integration Prerequisites
Before attempting this integration, you should:
- have a working and properly configured Novell Access Manager 3.1 Identity server
- be familiar with the Novell Access Manager Identity server architecture and administration configuration procedures
- be familiar with details in http://code.google.com/apis/apps/sso/saml_reference_implementation.html
High-level Overview of the SAML Posting Process
There are two ways to exchange SAML assertions: via artifacts through a backchannel direct server-to-server connection, or by using HTTP POSTs through the user's browser using a SAML form. Google Apps supports only the POSTing of the assertions through the user's browser, so the SAML profile defined at the Identity Server for the SAML relationship with Google Apps must use the POST binding.
Figure 1 shows the general process that Novell's SAML Identity server and Google Apps SAML service provider follow in granting access to the Google Apps services.
This above diagram illustrates the following steps.
- The user attemps to reach a hosted Google application, such as Gmail, Start Pages, or another Google service.
- Google generates a SAML authentication request. The SAML request is encoded and embedded into the URL for the Novell Access Manager Identity Servers SSO service.
- Google sends a 302 redirect to the user's browser. The redirect URL includes the encoded SAML authentication request that should be submitted to the Novell Identity Servers SSO service, which is defined on the Google single sign on configuration.
- The Novell Identity Server decodes the SAML request and extracts the URL for both Google's ACS (Assertion Consumer Service) and the user's destination URL (RelayState parameter). The Novell Identity server will attempt to authenticate the user against the back end user stores defined.
- Assuming the credentials are successfully validated and the user is authenticated to the Identity server, the Identity server will then generate a SAML response that contains the authenticated user's username. In accordance with the SAML 2.0 specification, this response is digitally signed with the certificate assigned to the Identity servers NIDP signing keystore.
- The Identity server encodes the SAML response and the RelayState parameter and returns that information to the user's browser. The response includes some javascript so that the browser automatically submits (using HTTP POST) the response to Google's ACS.
- Google's ACS verifies the SAML response using the Identity server signing certificate public key – this key is manually imported into the Google SAML configuration details during configuration. If the response is successfully verified, ACS redirects the user to the destination URL.
- The user has been redirected to the destination URL and is logged in to Google Apps.
Configuring Google Apps to integrate with Novell Access Manager
The Google Apps server is simply a SAML2 Service Provider (SP). It's goal is to
- redirect authentication requests to the SAML Identity Server (Novell Access Manager's IDP server).
In order to be able to do this, the Google Apps server must know the type of SAML Authentication request required to authenticate to the IDP server, and what URLs to send it to on the IDP server. In the screenshot below (figure 2), the following options must be enabled and populated:
- Enable Single Sign On: When enabled, it will single sign on (SSO) the user that authenticated to the IDP server, assuming that the SAML assertion includes the correct information to SSO the user.
- Sign-in page URL: This defines the URL on the IDP server where the Google Apps server will redirect the SAML authentication request to. When the user selects to authenticate to Google Apps via the Novell Access Manager IDP server, Google Apps will generate an Authentication request to be sent to this URL specified here.
- Sign-out page URL: This defines the URL on the IDP server where the Google Apps server will redirect logout requests to. When the user tries to logout of the Google Apps server, the logout request will be sent to the Novell Access Manager IDP server sign out URL so that the user will be logged out of both the SAML IDP and SP concurrently.
- Change password URL: This defines the URL that users will be redirected to would they want to change their password. This is not important in the SSO process being outlined here. This URL would typically interface into the user store so that the users credentials are updated.
- process the SAML assertion generated by the IDP server
When the user has successfully authenticate to the SAML IDP server, an assertion is generated by that IDP server and sent to the Google Apps service provider via the browser. The assertion generated by the IDP server is signed and the signature must be validated by the Google Apps server. The Verification certificate must include the correct signing certificate.
- Verification Certificate: When the Google Apps service provider processes the incoming assertion, it needs to be able to validate the signature before extracting the SSO credentials. This is done by matching the signing certificate from the assertion with the one imported in this field here. By default, the certificate that is assigned to the IDP server signing keystore must be exported to file and then uploaded into this 'Verification Certificate' field.
The only other thing that you need to be aware of are the username's defined. When the SAML assertion generated by the IDP server arrives at the Google Apps server, it will extract the username details from the assertion and validate the entry from the <NameID> SAML tag to see whether an existing user with a matching name exists on the Google Apps user database. In the example below, the username that will arrive within the SAML assertion will be admin, which matches what we have defined in the Google Apps user database.
Configuring Novell Access Manager to integrate with Google Apps
The Novell Access Manager Identity server is simply a SAML2 Identity Provider (IDP). It's goal is to
- process the incoming SAML Authentication request from the Service provider (SP)
- provide a mechanism for users to authenticate using the various authentication methods
- validate the credentials submitted by the user against the back end user store
- generate the SAML response, including assertion details, to the Google SP
In order to be able to do this, the Novell Access Manager Identity server must have a trust relationship with the Google Apps SP server. This is done by importing the GoogleSP metadata on the IDP server configuration page.
Before configuring the SAML details, a few basic configuration steps are required:
- the baseURL must be defined for the Novell Identity server. This URL will determine all the SAML endpoints required by Google at a later stage for single sign on, single logout, etc. This is a very easy process with Access Manager and simply involves configuring the 'base URL' setting on the main IDP configuration page. In the example below, we configured http://login.novellraptor.com. In a production environment, the URL would normally include a HTTPS scheme for security purposes.
Additional configuration details such as authentication types (name/password, radius, x509, etc) and user stores must also be defined but these tasks are outside the scope of this document. Check out 'Configuring Local Authentication' at http://www.novell.com/documentation/novellaccessmanager31/adminguide/?page=/documentation/novellaccessmanager31/adminguide/data/b2651cb.html if more details on this are required.
- An Attribute set must be defined on the IDP server so that we can include them in the SAML assertion to be sent to the Google server
From the IDP configuration page, select the 'Shared Settings' TAB (see '6.0 Defining Shared Settings' from http://www.novell.com/documentation/novellaccessmanager31/adminguide/?page=/documentation/novellaccessmanager31/adminguide/data/b2651cb.html). In here, we need to add a new Attribute set that will include the user cn that will be sent in the SAML assertion. Give the attribute set a logical name e.g. Google AppsAttrSet and simply add the LDAP cn attribute to the list – there is no need to map it to a remote attribute name.
Note: Failure to add this will result in NOT being able to select the right SAML NameID format at a later stage.Now we are ready to go and create the SAML trust relationship with Google ...
- Create the SAML relationship between the Novell Identity server and the Google service provider
When exchanging SAML data, a trust relationship must exist between the various providers exchanging the SAML information. Selecting the SAML2 TAB in the IDP configuration, the administrator can create a new SAML trusted service provider for the Google SP. When doing this, the trusted service provider metadata must be added. With the Google Apps SP, simply:
- add a logical name for the trusted provider e.g name of Google AppsSAML
- Change the source from 'metadata URL' to 'metadata text' and include the following string
<EntityDescriptor entityID="google.com" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"> <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress </NameIDFormat> <AssertionConsumerService index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.google.com/a/YOURDOMAIN/acs" /> </SPSSODescriptor> </EntityDescriptor>where YOURDOMAIN must match the domain that you have registered with Google. In our example setup, this domain is novellraptor.com
Note:- the NameIDFormat expected by Google is emailAddress, so make sure this format is defined correctly.
- there are no certificates required in the metadata for the SSO to work correctly
Assuming that the configuration has been done correctly, the 'metadata' TAB under the Google Apps service provider should look as follows:
- Define the Authentication response from Novell IDP to Google Apps SP
The configuration of the Authentication response is very important, in that the info sent by the IDP server in it's SAML assertion must match what is required for the Google Apps server to single sign on it's users. In the case of the Google Apps server, it requires the
- user CN ('admin' in our example) to be included within the <NameID> SAML assertion tag and
- NameID format must be of type emailAddress (which we already included in the imported metadata above)
- the SAML binding for the authentication response must be POST, and not the default Artifact
By selecting the Google Apps service provider in the Access Manager IDP configuration, all three requirements above may be satisfied from the 'Authentication Response' configuration page. The binding must be manually changed to POST, and the email name Identifier format must be enabled. After enabling the setting, add the value of LDAP attribute cn (will only be availble is step 2 of the IDP confuration steps above has been completed), and make it the default response type as shown below.
After all these changes are saved and applied, we are ready to start our tests.
Verifying SAML SSO between Novell Identity server and Google Apps
The testing of the setup simply involves bringing up a browser and accessing your Google Apps server, or application. Assuming that the setup is successful, the Google Apps server should allow you to sign on via your newly created trust relationship with the Novell Identity server. In our example, the option to Sign in to Novell exists on the Google Apps server.
Selecting the option to login via Novell, the Google Apps server will generate the SAML authentication request to the Novell IDP server with the appropriate settings. This request is sent via the browser to the single sign on URL defined on the Google Apps server and is encoded. It also includes a RelayState parameter that includes the URL the user was trying to access initially. This user will eventually be redirected back to this RelayState URL after successful authentication.
Figure 9 – GET request sent by browser to Novell IDP server with Authentication request
GET /nidp/saml2/sso?SAMLRequest=fVLLbtswELwX6D8QvFuShQJpCUuBmyCogbQVYqWH3mhpZTMld1kuJbd%2FX1pOkOTQADwNh%2FNY7uryj7NigsCGsJLLrJACsKPe4L6S9%2B3N4qO8rN%2B%2FW7F21qv1GA94B79H4CjSS2Q1X1RyDKhIs2GF2gGr2Knt%2BuutKrNC%2BUCROrJSbK4rOaDR2nukA4LrnRvIDfsdeUTAB%2F%2FQ94g7AvNLih9PscpTrA3zCBvkqDEmqCg%2BLYqLdNplqcoL9aH8KUXz6PTZ4LnBW7F2ZxKrL23bLJrv23YWmEwP4VtiV3JPtLeQdeRO9o1mNlOCB20ZpFgzQ4gp4BUhjw7CFsJkOri%2Fu63kIUbPKs%2BPx2P2LJPrHGkCa4P2kcIZ6ljW83zVXDG8GOzbBfRTAFk%2FW6zyF1L147%2Bd6myuG7Km%2ByvW1tLxKoCOqUsMY6pyQ8Hp%2BH%2B3ZbacEdMvhpmqRmQPnRkM9FLk9dn19YKktfkH&RelayState=https%3A%2F%2Fwww.google.com%2Fa%2Fnovellraptor.com%2FServiceLogin2%3Fcontinue%3Dhttp%253A%252F%252Fsites.google.com%252Fa%252Fnovellraptor.com%26service%3Djotspot%26passive%3Dtrue%26ul%3D1
The Novell IDP server decodes this Authentication request as:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="lahmmbkcfolnnjiknecoilgeegfpkjalgepmpimb" Version= "2.0" IssueInstant="2009-07-07T12:22:20Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ProviderName="google.com" IsPassive="false" AssertionConsumerServiceURL="https://www.google.com/a/novellraptor.com/acs"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">google.com</saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" /> </samlp:AuthnRequest>
Assuming that the Novell IDP server is capable of validating the source of this Authentication request (based on finding a matching trusted provider in it's SAML trusted provider configuration), the user will be prompted to login to the Novell Identity server. In our example, we have a simple non customised login page asking the user for name and password. This may be modified to ask for other credential details.
After the user submits the credentials, the Identity server will validate them against the back end user store. It will also retrieve the users LDAP CN based on the attribute set defined for our SAML Authentication response. Assuming the IDP server has all it needs, it will generate the SAML authentication response to the Google Apps server and single sign on the user. The resulting page will display the authenticated user at the application user was trying to access.
The SAML assertion sent to the Google Apps server Assertion Consumer service (ACS) includes the following details:
Type: sent using POST binding
Sent to: https://www.google.com/a/novellraptor.com/acs
RelayState: https://www.google.com/a/novellraptor.com/ServiceLogin2?continue=http%3A%2F%2Fsites.google.com%2Fa%2Fnovellraptor.com&service=jotspot&passive=true&ul=1
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Consent="urn:oasis:names:tc:SAML:2.0:consent:obtained" Destination="https://www.google.com/a/novellraptor.com/acs" ID="idLqzfqrf66Ip qo4Nnvh-SJ4Hw480" InResponseTo="linhmenlpodadmdpdmaeibldlidofddncfnlmdkb" IssueInstant="2009-07-07T12:37:46Z" Version="2.0"> <saml:Issuer>http://login.novellraptor.com:8080/nidp/saml2/metadata</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="idEpQmIfkoLar2UPsS1f3PT8iw6.w" IssueInstant="2009-07-07T12:37:46Z" Version="2.0"> : : Signature and certificate details : <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="http://login.novellraptor.com:8080/nidp/saml2/metadata" SPNameQualifier="google.c om">admin</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="linhmenlpodadmdpdmaeibldlidofddncfnlmdkb" NotOnOrAfter="2009-07-07T13:37:46Z" Recipient="https://www.google.co m/a/novellraptor.com/acs"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2009-07-07T12:32:46Z" NotOnOrAfter="2009-07-07T12:42:46Z"> <saml:AudienceRestriction> <saml:Audience>google.com</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2009-07-07T12:37:46Z" SessionIndex="1395C3ABB33ECC281054FB874B0A1332" SessionNotOnOrAfter="2009-07-07T13:37:46Z"> <saml:AuthnContext> <saml:AuthnContextDeclRef>name/password/uri</saml:AuthnContextDeclRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response>
Under the Subject header, we can see the NameID tag with the value of the authenticated users LDAP CN (admin in our example). This is what the Google Apps server will retrieve to authenticate the user.
Troubleshooting SAML assertion issues
Since we are dealing with the SAML POST binding, it can greatly simplify the troubleshooting process because the required SAML details (Authentication request and response) are all going through the browser. With the ability to decode the HTTP requests on the browser (ieHTTPHeaders or Firefox HTTP header plug ins on browser), one can decode the request and response to/from the Novell Identity server.
The SAMLResponse includes the assertion details, but is base64 encoded. Cut and pasting the SAMLResponse value into a base64 decoder will output the SAML response in legible format, with all appropriate tags. An example base64 online decoder is available at http://www.opinionatedgeek.com/dotnet/tools/Base64....
Another option to debug the entire authentication process at the Novell IDP server, including the SAML exchange is to enable verbose logging at the IDP server. By selecting the following IDP logging options, the /var/opt/novell/tomcat5/logs/catalina.out file will include all details required to troubleshoot SAML issues.
After applying the settings to the IDP server, browse the catalina.out file and make sure
- the trusted SAML provider loads successfully. A message should appear in the log file indicating that the trusted provider has loaded with no errors, as shown below.
<amLogEntry> 2009-07-02T11:29:22Z INFO NIDS Application: AM#500105038: AMDEVICEID#34006BA7269B3C54: Loaded trusted provider google. com of protocol SAML 2 </amLogEntry>
If errors were detected in the metadata, an error code will be displayed here and documented under 'Novell Access Manager 3.1 Event Codes
' at http://www.novell.com/documentation/novellaccessmanager31/eventcodes/?page=/documentation/novellaccessmanager31/eventcodes/data/bookinfo.html - Make sure that the SAML AuthnRequest arrives from the Google Apps service provider. The following statement should be visible in the catalina.out assuming the authentication request arrives:
************************* SAML2 Redirect message ******************************** Type: received RelayState: https://www.google.com/a/novellraptor.com/ServiceL... ervice=jotspot&passive=true&ul=1 <?xml version="1.0" encoding="UTF-8"?> <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="ihccdlkjlniihggimkebhdfdbkilphibhkbfpilm" Version="2.0" I ssueInstant="2009-07-02T11:13:37Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ProviderName="google.com" IsPass ive="false" AssertionConsumerServiceURL="https://www.google.com/a/novellraptor.com/acs"><saml:Issuer xmlns:saml="urn:oasis:names:tc: SAML:2.0:assertion">google.com</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format :unspecified" /></samlp:AuthnRequest> ************************* End SAML2 message ****************************
- Make sure that the Authentication response is sent from the IDP server to the Google Apps server. The status should always indicate success and not an error. The following shows a snippet where the NameIDFormat sent to the SAML SP was invalid
<samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder"> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"/> </samlp:StatusCode> </samlp:Status>
When all works fine, we should see the success status code, along with the assertion details, as follows. What is key is the response distination, subject (including NameID details) and certificate used to sign the response – the Google Apps server must be setup to match this.
************************* SAML2 POST message ******************************** Type: sent Sent to: https://www.google.com/a/novellraptor.com/acs RelayState: https://www.google.com/a/novellraptor.com/ServiceL... http%3A%2F%2Fsites.google.com%2Fa%2Fnovellraptor.com&service=jotspot&passive=true&ul=1 <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Consent="urn:o asis:names:tc:SAML:2.0:consent:obtained" Destination="https://www.google.com/a/novellraptor.com/acs" ID="idV-BWI5fJcpD6I9nze4BO7Nlm3dg" InResponseTo="mkkpibonipipiapijkgkpgandhaifeefoghhmofa" IssueInstant="2009-07-07T12:54:53Z" Version="2.0"> <saml:Issuer>http://login.novellraptor.com:8080/nidp/saml2/metadata</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="idTyHJPjSy77prq2.5iNC6Q9DpZcs" IssueInstant="2009-07-07T12:54:53Z" Version="2.0"> <saml:Issuer>http://login.novellraptor.com:8080/nidp/saml2/metadata</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsi g#"><ds:SignedInfo><CanonicalizationMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/10/xml-exc-c 14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#idTyHJPjSy77prq2.5iNC6Q9DpZcs "><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://ww w.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue x mlns="http://www.w3.org/2000/09/xmldsig#">dNzva6BR8tJzmVsKaJARe+oEiNE=</DigestValue></ds:Reference></ds:SignedInfo><SignatureValue x mlns="http://www.w3.org/2000/09/xmldsig#"> fqhpq17JgAiV1x39mWPJt29toGA5zAIOP58kv2NCrg3qIqhsccoSabAC5O4qgQTdGnGlekX1aTde BxmK71ZEd75bAXPDLY61J3XAXIDDyNRvUAKupdQ+Su1q4ob9XRkawfFR/pRQupAtyFf/WqnYrCFp 48bk/wQTak0Au1CA4cAT1o99vKz8zODEHIfW07FVHDX3IwLsqL3MK8P/pwqT6gUg9k5VbaU95sNb qGzKIreHF7D+3x4M1whJEN7myC5cK4IJMfAO4MpHsTgGUeLC3+iYKglKoQon9ujB9zA8nlBTz0qi ukBi2V3ZBurlb/m0lDDRLEi1d9+fXsCgo2L9ow== </SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate> : : </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid -format:emailAddress" NameQualifier="http://login.novellraptor.com:8080/nidp/saml2/metadata" SPNameQualifier="google.com">admin</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="mkkpibonipipiapijkgkpgandhaifeefoghhmofa" NotOnOrAfter="2009-07-07T13:54:53Z" Recipient="https://www.google.com/a/novellraptor.com/acs"/>< /saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2009-07-07T12:49:53Z" NotOnOrAfter="2009-07-07T12:59:53Z"> <saml:AudienceRestriction> <saml:Audience>google.com</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2009-07-07T12:54:53Z" SessionIndex="686AE9514D0F8A9EC8A3912A315C8B06" SessionNotOnOrAfter="2009-07-07T13:54:53Z"> <saml:AuthnContext> <saml:AuthnContextDeclRef>name/password/uri</saml:AuthnContextDeclRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> ************************* End SAML2 message ****************************
Disclaimer: As with everything else at Cool Solutions, this content is definitely not supported by Novell (so don't even think of calling Support if you try something and it blows up).
It was contributed by a community member and is published "as is." It seems to have worked for at least one person, and might work for you. But please be sure to test, test, test before you do anything drastic with it.
Related Articles
User Comments
Updating the Cool Solution
Submitted by nareshbk on 9 February 2012 - 6:47pm.
This is a great document but it is now 2 years old. Could you please update this document as settings in Google have changed a lot?
Couple of things: 1. If you can provide the URLs to be entered in Google as text instead of the screenshot, that would be great.
2. Could you also explain how users can specify custom authentication contracts?
Thanks a lot.
- Be the first to comment! To leave a comment you need to Login or Register














1