Bug 456712 - Added CLA functionnalities to My Account

Change-Id: Ibe42aa9eac3c3f590ac3936c52acdbe125da0b08
Signed-off-by: Eric Poirier <eric@eclipse.org>
diff --git a/eclipse.org-common/classes/users/cla.class.php b/eclipse.org-common/classes/users/cla.class.php
new file mode 100644
index 0000000..5b5cd33
--- /dev/null
+++ b/eclipse.org-common/classes/users/cla.class.php
@@ -0,0 +1,490 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2016 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Eric Poirier (Eclipse Foundation) - initial API and implementation
+ *******************************************************************************/
+
+require_once($_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/classes/friends/friend.class.php");
+
+class Cla {
+
+  private $App = NULL;
+
+  private $cla_document_id = "";
+
+  private $cla_expiry_date = "";
+
+  private $cla_fields = array();
+
+  private $cla_form_content = array();
+
+  private $cla_is_signed = NULL;
+
+  private $form = "";
+
+  private $Friend = NULL;
+
+  private $is_committer = "";
+
+  private $messages = array();
+
+  private $Session = NULL;
+
+  private $SiteLogin = NULL;
+
+  private $state = "";
+
+  private $uid = "";
+
+  public function Cla(App $App) {
+    $this->App = $App;
+    $this->Session = $this->App->useSession();
+    $this->Friend = $this->Session->getFriend();
+    $this->uid = $this->Friend->getUID();
+    $this->is_committer = $this->Friend->getIsCommitter();
+
+    // Get the current state
+    $this->state = filter_var($this->App->getHTTPParameter("state", "POST"), FILTER_SANITIZE_STRING);
+    $this->form = filter_var($this->App->getHTTPParameter("form_name", "POST"), FILTER_SANITIZE_STRING);
+    if (!empty($this->uid) && $this->form == "cla-form") {
+      switch ($this->state) {
+        case 'submit_cla':
+          $this->_submitClaDocument();
+          break;
+        case 'invalidate_cla':
+          $this->_invalidateClaDocument();
+          break;
+        case 'disable_unsigned_notification':
+          $this->_disableUnsignedNotification();
+          break;
+      }
+    }
+
+    // Check if the current user has a signed CLA
+    if ($this->_claIsSigned() === FALSE && isset($_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION']) && $_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION'] === '1') {
+      $this->_notifyUserOfUnsignedCla();
+    }
+  }
+
+  /**
+   * This function returns the CLA expiry date
+   *
+   * @return string
+   * */
+  public function getClaExpiryDate() {
+    return $this->cla_expiry_date;
+  }
+
+  /**
+   * These functions returns the text to put on the CLA form
+   * @param $key - String containing a specified key
+   * @return string
+   * */
+  public function getClaFormContent($key = "") {
+    if (!empty($key) && isset($this->cla_form_content[$key])) {
+      return $this->cla_form_content[$key];
+    }
+    return '';
+  }
+
+  /**
+   * This function sets the CLA fields values from what's being posted from the form
+   * */
+  public function getFieldValues($field = "") {
+    $this->cla_fields = array(
+      'Question 1' => filter_var($this->App->getHTTPParameter("question_1", "POST"), FILTER_SANITIZE_NUMBER_INT),
+      'Question 2' => filter_var($this->App->getHTTPParameter("question_2", "POST"), FILTER_SANITIZE_NUMBER_INT),
+      'Question 3' => filter_var($this->App->getHTTPParameter("question_3", "POST"), FILTER_SANITIZE_NUMBER_INT),
+      'Question 4' => filter_var($this->App->getHTTPParameter("question_4", "POST"), FILTER_SANITIZE_NUMBER_INT),
+      'Email' => filter_var($this->App->getHTTPParameter("email", "POST"), FILTER_SANITIZE_EMAIL),
+      'Legal Name' => filter_var($this->App->getHTTPParameter("legal_name", "POST"), FILTER_SANITIZE_STRING),
+      'Public Name' => filter_var($this->App->getHTTPParameter("public_name", "POST"), FILTER_SANITIZE_STRING),
+      'Employer' => filter_var($this->App->getHTTPParameter("employer", "POST"), FILTER_SANITIZE_STRING),
+      'Address' => filter_var($this->App->getHTTPParameter("address", "POST"), FILTER_SANITIZE_STRING),
+      'Agree' => filter_var($this->App->getHTTPParameter("agree", "POST"), FILTER_SANITIZE_STRING)
+    );
+
+    // Return the field if we're asking for one in particular
+    if (!empty($field) && !empty($this->cla_fields[$field])) {
+      return $this->cla_fields[$field];
+    }
+  }
+
+  public function getClaIsSigned() {
+    if (is_null($this->cla_is_signed)) {
+      $this->cla_is_signed = $this->_claIsSigned();
+    }
+    return $this->cla_is_signed;
+  }
+
+  /**
+   * This function returns an Array containing the user's signed CLA
+   *
+   * @return array OR string
+   * */
+  public function getSignedClaDocument() {
+    if (!empty($this->uid)) {
+      $sql ="SELECT ScannedDocumentBLOB From PeopleDocuments
+             WHERE PersonID = " . $this->App->returnQuotedString($this->App->sqlSanitize($this->uid))."
+             AND ExpirationDate IS NULL";
+      $result = $this->App->foundation_sql($sql);
+
+      if ($row = mysql_fetch_assoc($result)) {
+        $decode = json_decode($row['ScannedDocumentBLOB'], TRUE);
+        $decode['cla_doc'] = base64_decode($decode['cla_doc']);
+        return $decode;
+      }
+    }
+    return "Document not signed.";
+  }
+
+  /**
+   * This function puts the right content on the CLA tab
+   * */
+  public function outputPage() {
+    switch ($this->_claIsSigned()){
+      case TRUE:
+        include $_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/classes/users/tpl/cla_record.tpl.php";
+        break;
+      case FALSE:
+        $this->_claFormContent();
+        include $_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/classes/users/tpl/cla_form.tpl.php";
+        break;
+    }
+  }
+
+  /**
+   * This function insert rows in the account_requests and SYS_EvtLog tables
+   * depending on $action is specified
+   *
+   * @param $action - Validate or invalidate a CLA
+   */
+  private function _actionLdapGroupRecord($action) {
+    $email = $this->Friend->getEmail();
+    $accepted_actions = array(
+        'CLA_SIGNED',
+        'CLA_INVALIDATED'
+    );
+    if ($this->uid && in_array($action, $accepted_actions) && !empty($email)) {
+      //Insert the request to add to LDAP.
+      $sql = "INSERT INTO account_requests
+              (email,fname,lname,password,ip,token,req_when)
+              values (
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($email)).",
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($this->Friend->getFirstName())).",
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($this->Friend->getLastName())).",
+                'eclipsecla',
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($_SERVER['REMOTE_ADDR'])).",
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($action)).",
+                NOW()
+              )";
+      $result = $this->App->eclipse_sql($sql);
+
+      // Log that this event occurred
+      $sql = "INSERT INTO SYS_EvtLog
+              (LogTable,PK1,PK2,LogAction,uid,EvtDateTime)
+              values (
+                'cla',
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($this->uid)).",
+                'EclipseCLA-v1',
+                ".$this->App->returnQuotedString($this->App->sqlSanitize($action)).",
+                'cla_service',
+                NOW()
+              )";
+      $result = $this->App->foundation_sql($sql);
+    }
+    else {
+      $this->App->setSystemMessage('account_requests', "There's been an error updated the LDAP group record. (LDAP-01)", "danger");
+    }
+  }
+
+  /**
+   * This function check if the current user has access to sign the CLA
+   * @return BOOL
+   * */
+  private function _allowSigning() {
+
+    // If user is logged in
+    $email = $this->Friend->getEmail();
+    if (!empty($this->uid) || !empty($email) || $this->Friend->checkUserIsFoundationStaff()) {
+      return TRUE;
+    }
+
+    // The user is not logged in and is not part of the foundation staff
+    return FALSE;
+  }
+
+  /**
+   * This internal function prepares a data array and converts it to JSON,
+   * it is a helper function for contributor_agreement__insert_cla_document
+   *
+   * @return string JSON encoded string.
+   */
+  private function _claDocumentInJson() {
+
+    $cla_document = fopen('http://www.eclipse.org/legal/CLA.html', 'r');
+    $data = array(
+      'legal_name' => $this->cla_fields['Legal Name'],
+      'public_name' => $this->cla_fields['Public Name'],
+      'employer' => $this->cla_fields['Employer'],
+      'address' => $this->cla_fields['Address'],
+      'email' => $this->cla_fields['Email'],
+      'question_1' => $this->cla_fields['Question 1'],
+      'question_2' => $this->cla_fields['Question 2'],
+      'question_3' => $this->cla_fields['Question 3'],
+      'question_4' => $this->cla_fields['Question 4'],
+      'agree' => $this->cla_fields['Agree'],
+      'cla_doc' => base64_encode(stream_get_contents($cla_document)),
+    );
+    fclose($cla_document);
+    return json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
+  }
+
+  /**
+   * This function fetches content from the CLA html file
+   * */
+  private function _claFormContent() {
+
+    $cla_document = new DomDocument();
+    $cla_document->loadhtmlfile('http://www.eclipse.org/legal/CLA.html');
+
+    // Remove the #reference DIV
+    $reference = $cla_document->getElementById('reference');
+    $reference->parentNode->removeChild($reference);
+
+    // Fetching the pieces of content by ID
+    $question1 = $cla_document->getElementById('question1');
+    $question2 = $cla_document->getElementById('question2');
+    $question3 = $cla_document->getElementById('question3');
+    $question4 = $cla_document->getElementById('question4');
+    $text1 = $cla_document->getElementById('text1');
+    $text2 = $cla_document->getElementById('text2');
+    $text3 = $cla_document->getElementById('text3');
+
+    $this->cla_form_content = array(
+      'question_1' => $question1->nodeValue,
+      'question_2' => $question2->nodeValue,
+      'question_3' => $question3->nodeValue,
+      'question_4' => $question4->nodeValue,
+      'text_1' => $cla_document->saveXML($text1),
+      'text_2' => $cla_document->saveXML($text2),
+      'text_3' => $cla_document->saveXML($text3),
+    );
+  }
+
+  /**
+   * Ckeck if Effective Date the CLA was signed for the logged in user,
+   * or FALSE if no record was found
+   *
+   * @return string or BOOL FALSE
+   */
+  private function _claIsSigned() {
+    $cla_document_id = $this->_getClaDocumentId();
+    if (!empty($this->uid) && !empty($cla_document_id)) {
+      $sql = "SELECT EffectiveDate FROM PeopleDocuments
+              WHERE PersonID = ". $this->App->returnQuotedString($this->App->sqlSanitize($this->uid)) ."
+              AND DocumentID = ". $this->App->returnQuotedString($this->App->sqlSanitize($cla_document_id)) ."
+              AND ExpirationDate IS NULL";
+      $result = $this->App->foundation_sql($sql);
+
+      if ($row = mysql_fetch_assoc($result)) {
+        // Returns the Expiry date and making sure we remove the time from the date.
+        $this->cla_expiry_date = date("Y-m-d", strtotime('+3 years', strtotime($row['EffectiveDate'])));
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+
+  /**
+   * This function sets a cookie to hide the unsigned notification message
+   * */
+  private function _disableUnsignedNotification() {
+    setcookie ('ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION', '1',  time() + 3600 * 24 * 1095, '/' );
+  }
+
+  /**
+   * This internal function returns the Document ID for CLAs
+   * @return string OR NULL
+   * */
+  private function _getClaDocumentId() {
+    $sql = "SELECT DocumentId FROM SYS_Documents
+            WHERE Description='Contributor License Agreement'
+            AND Version=1 AND Type='IN'";
+    $result = $this->App->foundation_sql($sql);
+    if ($row = mysql_fetch_assoc($result)) {
+      return $row['DocumentId'];
+    }
+    return NULL;
+  }
+
+/**
+ * This function invalidates a user's CLA document
+ */
+  private function _invalidateClaDocument() {
+    if (!empty($this->uid) && $this->_getClaDocumentId()) {
+      //First we need to find the active CLA record.
+      $sql = "SELECT PersonID, EffectiveDate
+                FROM PeopleDocuments
+                WHERE PersonID = " . $this->App->returnQuotedString($this->App->sqlSanitize($this->uid)) . "
+                AND DocumentID = " . $this->App->returnQuotedString($this->App->sqlSanitize($this->_getClaDocumentId())) . "
+                AND ExpirationDate IS NULL";
+      $result = $this->App->foundation_sql($sql);
+
+      if ($myrow = mysql_fetch_assoc($result)) {
+         // Log that this event occurred Note that foundationdb uses SYS_ModLog instead of SYS_EvtLog;
+        $sql = "INSERT INTO SYS_ModLog
+                  (LogTable,PK1,PK2,LogAction,PersonID,ModDateTime)
+                  values (
+                    'cla',
+                    'cla_service',
+                    'EclipseCLA-v1',
+                    'INVALIDATE_CLA DOCUMENT',
+                    ".$this->App->returnQuotedString($this->App->sqlSanitize($myrow['PersonID'])).",
+                    NOW()
+                  )";
+        $result = $this->App->foundation_sql($sql);
+
+        $sql = "UPDATE PeopleDocuments
+                SET ExpirationDate=NOW()
+                WHERE PersonID = ".$this->App->returnQuotedString($this->App->sqlSanitize($myrow['PersonID']))."
+                AND DocumentID = ".$this->App->returnQuotedString($this->App->sqlSanitize($this->_getClaDocumentId()))."
+                AND EffectiveDate = ".$this->App->returnQuotedString($this->App->sqlSanitize($myrow['EffectiveDate']));
+        $result = $this->App->foundation_sql($sql);
+
+        //Invalidate the users LDAP group.
+        $this->_actionLdapGroupRecord('CLA_INVALIDATED');
+
+        // Making sure we add the notification back in the page
+        if (isset($_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION'])) {
+          unset($_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION']);
+          setcookie('ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION', '', time() - 3600, '/');
+        }
+
+
+        // Create success message
+        $this->App->setSystemMessage('invalidate_cla','You have successfuly invalidated your CLA.','success');
+      }
+      else {
+        // Create error message
+        $this->App->setSystemMessage('invalidate_cla','An attempt to invalidate the CLA failed because we were unable to find the CLA that matches. (LDAP-02)','danger');
+      }
+    }
+  }
+
+  /**
+   * This function let the user know about an unsigned CLA
+   * */
+  private function _notifyUserOfUnsignedCla() {
+
+    // Check if user don't want to see the notification
+    if (isset($_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION']) && $_COOKIE['ECLIPSE_CLA_DISABLE_UNSIGNED_NOTIFICATION'] === '1') {
+      return FALSE;
+    }
+
+    $committer_string = '';
+    if ($this->is_committer) {
+      $committer_string = ' for which you are not a committer ';
+    }
+
+    $message = '
+      <p>In order to contribute code to an Eclipse Foundation Project ' . $committer_string . 'you will be required to sign a Contributor License Agreement (CLA).</p>
+      <form action="" method="POST">
+        <input type="hidden" name="unsigned_cla_notification" value="1">
+        <input type="hidden" name="state" value="disable_unsigned_notification">
+        <ul class="list-inline margin-top-10 margin-bottom-0">
+          <li><a class="small btn btn-primary" href="http://www.eclipse.org/legal/clafaq.php">What is a CLA?</a></li>
+          <li><a class="small btn btn-primary" href="#open_tab_cla">Sign your CLA</a></li>
+          <li><button class="small btn btn-primary">Disable this message</button></li>
+        </ul>
+      </form>';
+
+    $this->App->setSystemMessage('unsigned_cla',$message,'info');
+  }
+
+  /**
+   * This internal function inserts a new CLA document based off the form data submitted.
+   */
+  private function _submitClaDocument() {
+
+    // Get values from the submitted form
+    $this->getFieldValues();
+
+    // Check if the sumitted fields validate and if there is no signed CLA for this user
+    if ($this->_allowSigning() && $this->_validatedClaFields() && !$this->_claIsSigned() && $this->_getClaDocumentId()) {
+      // get the CLA document in Json format
+      $blob = $this->_claDocumentInJson();
+
+      $sql = "INSERT INTO PeopleDocuments
+                (PersonId,DocumentId,Version,EffectiveDate,ReceivedDate,
+                ScannedDocumentBLOB,ScannedDocumentMime,ScannedDocumentBytes,
+                ScannedDocumentFileName,Comments)
+              VALUES (
+                ". $this->App->returnQuotedString($this->App->sqlSanitize($this->uid)) .",
+                ". $this->App->returnQuotedString($this->App->sqlSanitize($this->_getClaDocumentId())) .",
+                1,
+                now(),
+                now(),
+                '". $blob ."',
+                'application/json',
+                ". strlen($blob) .",
+                'eclipse-cla.json',
+                'Automatically generated CLA'
+              )";
+      $result = $this->App->foundation_sql($sql);
+
+      // Log that this event occurred
+      $sql = "INSERT INTO SYS_ModLog
+                (LogTable,PK1,PK2,LogAction,PersonID,ModDateTime)
+                VALUES (
+                  'cla',
+                  ". $this->App->returnQuotedString($this->App->sqlSanitize($this->uid)) .",
+                  'EclipseCLA-v1',
+                  'NEW CLA DOCUMENT',
+                  'cla_service',
+                  NOW()
+                )";
+      $result = $this->App->foundation_sql($sql);
+
+      // Submit the users LDAP group.
+      $this->_actionLdapGroupRecord('CLA_SIGNED');
+
+      $this->App->setSystemMessage('submit_cla',"You successfully submitted the CLA!",'success');
+    }
+    else {
+      $this->App->setSystemMessage('submit_cla',"Error, the CLA have not been submitted. (LDAP-03)",'danger');
+    }
+  }
+
+  /**
+   * This function checks if all the fields from the form validates
+   *
+   * @return BOOL
+   * */
+  private function _validatedClaFields() {
+    $is_valid = TRUE;
+    foreach ($this->cla_fields as $field_name => $field_value) {
+      if (strpos($field_name, 'Question') !== FALSE && $field_value !== "1") {
+        $this->App->setSystemMessage('submit_cla','You must accept ' . $field_name,'danger');
+        $is_valid = FALSE;
+      }
+      if (($field_name == 'Email' || $field_name == 'Legal Name' || $field_name == 'Employer' || $field_name == 'Address') && empty($field_value)) {
+        $this->App->setSystemMessage('submit_cla','You must enter your ' . $field_name,'danger');
+        $is_valid = FALSE;
+      }
+      if ($field_name == 'Agree' && $field_value !== 'I AGREE') {
+        $this->App->setSystemMessage('submit_cla','You must enter "I AGREE" in the Electronic Signature field.','danger');
+        $is_valid = FALSE;
+      }
+    }
+    return $is_valid;
+  }
+
+}
\ No newline at end of file
diff --git a/eclipse.org-common/classes/users/tpl/cla_form.tpl.php b/eclipse.org-common/classes/users/tpl/cla_form.tpl.php
new file mode 100644
index 0000000..d7b6015
--- /dev/null
+++ b/eclipse.org-common/classes/users/tpl/cla_form.tpl.php
@@ -0,0 +1,157 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2016 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Eric Poirier (Eclipse Foundation) - initial API and implementation
+ *******************************************************************************/
+?>
+<?php if (is_a($this, 'Cla') && $this->Friend->getUID()): ?>
+  <form id="frm_cla" name="frm_cla" action="#open_tab_cla" method="post">
+    <?php print $this->getClaFormContent('text_1'); ?>
+    <ul>
+      <li><?php print $this->getClaFormContent('question_1'); ?></li>
+      <li><?php print $this->getClaFormContent('question_2'); ?></li>
+      <li><?php print $this->getClaFormContent('question_3'); ?></li>
+      <li><?php print $this->getClaFormContent('question_4'); ?></li>
+    </ul>
+    <?php print $this->getClaFormContent('text_2'); ?>
+    <?php print $this->getClaFormContent('text_3'); ?>
+    <div class="well">
+      <h2>YOU ACCEPT ...</h2>
+
+      <div class="form-group clearfix">
+        <div class="col-xs-1 position-static">
+          <input <?php if ($this->getFieldValues('Question 1') === "1"){print 'checked';}?>
+          class="committer-license-agreement-checkbox form-checkbox required"
+          type="checkbox" id="edit-question-1" name="question_1" value="1" />
+        </div>
+        <div class="col-xs-22">
+          <label class="option" for="edit-question-1">Question 1 <span
+          class="form-required" title="This field is required.">*</span></label>
+          <div class="description"><?php print $this->getClaFormContent('question_1'); ?></div>
+        </div>
+      </div>
+
+      <div class="form-group clearfix">
+        <div class="col-xs-1 position-static">
+      <input <?php if ($this->getFieldValues('Question 2') === "1"){print 'checked';}?>
+        class="committer-license-agreement-checkbox form-checkbox required"
+        type="checkbox" id="edit-question-2" name="question_2" value="1" />
+      </div>
+        <div class="col-xs-22">
+      <label class="option" for="edit-question-2">Question 2 <span
+        class="form-required" title="This field is required.">*</span></label>
+      <div class="description"><?php print $this->getClaFormContent('question_2'); ?></div>
+        </div>
+      </div>
+
+      <div class="form-group clearfix">
+        <div class="col-xs-1 position-static">
+      <input <?php if ($this->getFieldValues('Question 3') === "1"){print 'checked';}?>
+        class="committer-license-agreement-checkbox form-checkbox required"
+        type="checkbox" id="edit-question-3" name="question_3" value="1" />
+      </div>
+        <div class="col-xs-22">
+      <label class="option" for="edit-question-3">Question 3 <span
+        class="form-required" title="This field is required.">*</span></label>
+      <div class="description"><?php print $this->getClaFormContent('question_3'); ?></div>
+        </div></div>
+
+      <div class="form-group clearfix">
+        <div class="col-xs-1 position-static">
+      <input <?php if ($this->getFieldValues('Question 4') === "1"){print 'checked';}?>
+        class="committer-license-agreement-checkbox form-checkbox required"
+        type="checkbox" id="edit-question-4" name="question_4" value="1" />
+      </div>
+        <div class="col-xs-22">
+      <label class="option" for="edit-question-4">Question 4 <span
+        class="form-required" title="This field is required.">*</span></label>
+      <div class="description"><?php print $this->getClaFormContent('question_4'); ?></div>
+      </div></div>
+
+      <div class="form-group">
+      <?php print $this->getClaFormContent('text_2'); ?>
+      </div>
+      <div class="form-group">
+      <label for="edit-agree">Electronic Signature <span
+        class="form-required" title="This field is required.">*</span></label>
+      <input class="form-control form-text required" type="text"
+        id="edit-agree" name="agree" value="<?php print $this->getFieldValues('Agree'); ?>" size="60" maxlength="128" />
+      <div class="description">Type &quot;I AGREE&quot; to accept the
+        terms above</div>
+      </div>
+    </div>
+
+
+      <p><strong>You represent that the information provided below is accurate.</strong></p>
+
+    <div class="form-group">
+      <label for="edit-email">Email Address <span class="form-required"
+        title="This field is required.">*</span></label>
+      <input readonly class="form-control form-text"
+        type="text" id="edit-email" name="email"
+        value="<?php print $this->Friend->getEmail(); ?>" size="60" maxlength="128" />
+      <div class="description">If you wish to use a different email
+        address you must first change the primary email address associated
+        with your account</div>
+
+    </div>
+    <div class="form-group">
+      <label for="edit-legal-name">Legal Name <span class="form-required"
+        title="This field is required.">*</span></label>
+      <input readonly
+        class="form-control form-text" type="text"
+        id="edit-legal-name" name="legal_name" value="<?php print $this->Friend->getFirstName() . ' ' . $this->Friend->getLastName(); ?>"
+        size="60" maxlength="128" />
+      <div class="description">Your full name as written in your passport
+        (e.g. First Middle Lastname)</div>
+    </div>
+
+    <div class="form-group">
+      <label for="edit-public-name">Public Name </label>
+      <input
+        class="form-control form-text" type="text" id="edit-public-name"
+        name="public_name" value="<?php print $this->getFieldValues('Public Name'); ?>" size="60" maxlength="128" />
+      <div class="description">Your full name, alias, or nickname that
+        people call you in the Project (e.g. First Lastname) - leave this
+        field empty if it&#039;s identical to your legal name</div>
+    </div>
+
+    <div class="form-group">
+      <label for="edit-employer">Employer <span class="form-required"
+        title="This field is required.">*</span></label> <input
+        class="form-control form-text required" type="text"
+        id="edit-employer" name="employer" value="<?php print $this->getFieldValues('Employer'); ?>" size="60"
+        maxlength="128" />
+      <div class="description">Your employer - you may choose to enter
+        &quot;Self-employed&quot; or &quot;Student&quot; in this field</div>
+    </div>
+
+    <div class="form-group">
+      <label for="edit-address">Mailing Address <span
+        class="form-required" title="This field is required.">*</span></label>
+      <div class="form-textarea-wrapper resizable">
+        <textarea class="form-control form-textarea required"
+          id="edit-address" name="address" cols="60" rows="5"><?php print $this->getFieldValues('Address'); ?></textarea>
+      </div>
+      <div class="description">Your physical mailing address</div>
+    </div>
+
+    <div class="form-group">
+      <input type="hidden" name="state" value="submit_cla">
+      <input type="hidden" name="form_name" value="cla-form">
+      <button class="btn btn-default form-submit" id="edit-submit" name="op"
+        value="Accept" type="submit">Accept</button>
+      </div>
+      <p class="help_text">
+        If you have any questions about this agreement, licensing, or
+        anything related to intellectual property at the Eclipse Foundation,
+        please send an email to <a href="mailto:license@eclipse.org">license@eclipse.org</a>.
+      </p>
+  </form>
+<?php endif; ?>
\ No newline at end of file
diff --git a/eclipse.org-common/classes/users/tpl/cla_record.tpl.php b/eclipse.org-common/classes/users/tpl/cla_record.tpl.php
new file mode 100644
index 0000000..1afb8c7
--- /dev/null
+++ b/eclipse.org-common/classes/users/tpl/cla_record.tpl.php
@@ -0,0 +1,28 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2016 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Eric Poirier (Eclipse Foundation) - initial API and implementation
+ *******************************************************************************/
+?>
+
+<?php if (is_a($this, 'Cla') && $this->Friend->getUID()): ?>
+  <div class="alert alert-info" role="alert">
+    <p>The Contributor License Agreement that we have on record for
+    you will expire on <?php print $this->getClaExpiryDate(); ?></p>
+  </div>
+  <p>If you've changed employers or your contact information,
+  please invalidate your current CLA and complete the form again.
+  <strong>Note that if you invalidate your CLA, it cannot be undone;
+  you will be prompted to sign a new CLA.</strong></p>
+  <form action="#open_tab_cla" method="POST">
+    <input type="hidden" name="state" value="invalidate_cla">
+    <input type="hidden" name="form_name" value="cla-form">
+    <button class="btn btn-primary">Invalidate CLA</button>
+  </form>
+<?php endif; ?>
\ No newline at end of file
diff --git a/eclipse.org-common/system/app.class.php b/eclipse.org-common/system/app.class.php
index 95e7ec7..df86d58 100644
--- a/eclipse.org-common/system/app.class.php
+++ b/eclipse.org-common/system/app.class.php
@@ -181,6 +181,15 @@
   }
 
   /**
+   * This function returns the CLA object
+   * @return object
+   * */
+  public function getCla() {
+    require_once($_SERVER['DOCUMENT_ROOT'] . "/eclipse.org-common/classes/users/cla.class.php");
+    return new Cla($this);
+  }
+
+  /**
    * This function sets System Messages
    * @param $name - string containing the name of the message
    * @param $msg  - string containing the message itself
@@ -235,8 +244,8 @@
 
     $server['dev'] = array(
       'cookie' => '.eclipse.local',
-      'domain' => 'www.eclipse.local',
-      'dev_domain' => 'dev.eclipse.local',
+      'domain' => 'www.eclipse.local:50243',
+      'dev_domain' => 'dev.eclipse.local:51143',
       'allowed_hosts' => array(
         'eclipse.local',
         'www.eclipse.local',
diff --git a/eclipse.org-common/themes/polarsys/app.php b/eclipse.org-common/themes/polarsys/app.php
index 84a26b7..1537fa9 100644
--- a/eclipse.org-common/themes/polarsys/app.php
+++ b/eclipse.org-common/themes/polarsys/app.php
@@ -35,6 +35,8 @@
 
     $base_url = $App->getWWWPrefix() . '/';
     $Session = $App->useSession();
+    $domains = $variables['page']['App']->getEclipseDomain();
+    $dev_domain = 'https://'.$domains['dev_domain'];
 
     $variables['session'] = array(
       'Friend' => NULL,
@@ -45,14 +47,14 @@
     $variables['url'] = $base_url;
 
     $variables['session']['Friend'] = $Session->getFriend();
-    $variables['session']['create_account_link'] = '<a href="https://dev.eclipse.org/site_login/createaccount.php"><i class="fa fa-user fa-fw"></i> Create account</a>';
+    $variables['session']['create_account_link'] = '<a href="'.$dev_domain.'/site_login/createaccount.php"><i class="fa fa-user fa-fw"></i> Create account</a>';
     $variables['session']['my_account_link'] = '<a href="https://www.polarsys.org/user/login/sso"><i class="fa fa-sign-in fa-fw"></i> Log in</a>';
     $variables['session']['logout'] = '';
     if ($Session->isLoggedIn()) {
       $variables['session']['name'] = $variables['session']['Friend']->getFirstName();
       $variables['session']['last_name'] = $variables['session']['Friend']->getLastName();
       $variables['session']['create_account_link'] = 'Welcome, ' . $variables['session']['name'] . ' ' . $variables['session']['last_name'];
-      $variables['session']['my_account_link'] = '<a href="https://dev.eclipse.org/site_login/myaccount.php" class=""><i class="fa fa-edit fa-fw"></i> Edit my account</a>';
+      $variables['session']['my_account_link'] = '<a href="'.$dev_domain.'/site_login/myaccount.php#open_tab_profile" class=""><i class="fa fa-edit fa-fw"></i> Edit my account</a>';
       // Adding <li> with logout because we only display
       // two options if the user is not logged in.
       $variables['session']['logout'] = '<li><a href="https://www.polarsys.org/user/logout"><i class="fa fa-power-off fa-fw"></i> Log out</a></li>';
diff --git a/eclipse.org-common/themes/solstice/app.php b/eclipse.org-common/themes/solstice/app.php
index 5d8416c..0107644 100644
--- a/eclipse.org-common/themes/solstice/app.php
+++ b/eclipse.org-common/themes/solstice/app.php
@@ -35,6 +35,8 @@
 
     $base_url = $App->getWWWPrefix() . '/';
     $Session = $App->useSession();
+    $domains = $variables['page']['App']->getEclipseDomain();
+    $dev_domain = 'https://'.$domains['dev_domain'];
 
     $variables['session'] = array(
       'Friend' => NULL,
@@ -45,17 +47,17 @@
     $variables['url'] = $base_url;
 
     $variables['session']['Friend'] = $Session->getFriend();
-    $variables['session']['create_account_link'] = '<a href="https://dev.eclipse.org/site_login/createaccount.php"><i class="fa fa-user fa-fw"></i> Create account</a>';
-    $variables['session']['my_account_link'] = '<a href="https://dev.eclipse.org/site_login/?takemeback=' . $App->getWWWPrefix() . $_SERVER['REQUEST_URI'] . '"><i class="fa fa-sign-in fa-fw"></i> Log in</a>';
+    $variables['session']['create_account_link'] = '<a href="'.$dev_domain.'/site_login/createaccount.php"><i class="fa fa-user fa-fw"></i> Create account</a>';
+    $variables['session']['my_account_link'] = '<a href="'.$dev_domain.'/site_login/?takemeback=' . $App->getWWWPrefix() . $_SERVER['REQUEST_URI'] . '"><i class="fa fa-sign-in fa-fw"></i> Log in</a>';
     $variables['session']['logout'] = '';
     if ($Session->isLoggedIn()) {
       $variables['session']['name'] = $variables['session']['Friend']->getFirstName();
       $variables['session']['last_name'] = $variables['session']['Friend']->getLastName();
       $variables['session']['create_account_link'] = 'Welcome, ' . $variables['session']['name'] . ' ' . $variables['session']['last_name'];
-      $variables['session']['my_account_link'] = '<a href="https://dev.eclipse.org/site_login/myaccount.php" class=""><i class="fa fa-edit fa-fw"></i> Edit my account</a>';
+      $variables['session']['my_account_link'] = '<a href="'.$dev_domain.'/site_login/myaccount.php#open_tab_profile" class="" data-tab-destination="tab-profile"><i class="fa fa-edit fa-fw"></i> Edit my account</a>';
       // Adding <li> with logout because we only display
       // two options if the user is not logged in.
-      $variables['session']['logout'] = '<li><a href="https://dev.eclipse.org/site_login/logout.php"><i class="fa fa-power-off fa-fw"></i> Log out</a></li>';
+      $variables['session']['logout'] = '<li><a href="'.$dev_domain.'/site_login/logout.php"><i class="fa fa-power-off fa-fw"></i> Log out</a></li>';
     }
 
     // Breadcrumbs
diff --git a/site_login/content/en_myaccount.php b/site_login/content/en_myaccount.php
index 0bc9850..e032c0e 100644
--- a/site_login/content/en_myaccount.php
+++ b/site_login/content/en_myaccount.php
@@ -17,6 +17,7 @@
   $pageTitle = 'My Account';
 
 ?>
+
 <div class="container padding-top-25 padding-bottom-25">
   <div id="maincontent">
     <div id="midcolumn">
@@ -27,9 +28,10 @@
       <?php endif;?>
       <?php print $Sitelogin->getSystemMessage();?>
       <ul class="nav nav-tabs" role="tablist">
-        <li class="active"><a href="#open_tab_profile" role="tab" data-toggle="tab" id="tab-profile">Edit Profile</a></li>
+        <li <?php print ($Cla->getClaIsSigned() === TRUE ? 'class="active"' : '');?>><a href="#open_tab_profile" role="tab" data-toggle="tab" id="tab-profile">Edit Profile</a></li>
         <li><a href="#open_tab_accountsettings" role="tab" data-toggle="tab" id="tab-accountsettings">Account Settings</a></li>
         <li><a data-url="<?php print $Sitelogin->getDomain(); ?>/site_login/subscriptions.php" href="#open_tab_subscriptions" role="tab" data-toggle="tab" id="tab-subscriptions">Subscriptions</a></li>
+        <li <?php print ($Cla->getClaIsSigned() === FALSE ? 'class="active"' : '');?>><a href="#open_tab_cla" role="tab" data-toggle="tab" id="tab-accountsettings">Eclipse CLA</a></li>
 
         <?php if ($var_welcomeback['friend']['is_benefit']) :?>
           <li><a href="#foe" role="tab" data-toggle="tab" id="tab-profile">Friends of Eclipse</a></li>
@@ -37,7 +39,7 @@
 
       </ul>
       <div class="tab-content">
-        <div class="tab-pane fade in active" id="open_tab_profile">
+        <div class="tab-pane fade in <?php print ($Cla->getClaIsSigned() === TRUE ? 'active' : '');?>" id="open_tab_profile">
           <?php include "myaccount/en_profile.php" ?>
         </div>
 
@@ -49,6 +51,10 @@
           <noscript>You need to enable Javascript to manage your subscriptions</noscript>
         </div>
 
+        <div class="tab-pane fade in <?php print ($Cla->getClaIsSigned() === FALSE ? 'active' : '');?>" id="open_tab_cla">
+          <?php $Cla->outputPage(); ?>
+        </div>
+
         <?php if ($var_welcomeback['friend']['is_benefit']) :?>
           <div class="tab-pane fade" id="foe">
             <?php include "myaccount/en_friends_info.php" ?>
diff --git a/site_login/myaccount.php b/site_login/myaccount.php
index 8ed08df..5581972 100755
--- a/site_login/myaccount.php
+++ b/site_login/myaccount.php
@@ -22,6 +22,7 @@
   $Menu = new Menu();
   $Sitelogin = new Sitelogin();
   $InfraBlock = new InfraBlock();
+  $Cla = $App->getCla();
   $App->preventCaching();
 
   $App->useSession(TRUE);
diff --git a/site_login/public/css/styles.min.css b/site_login/public/css/styles.min.css
index e824add..9eee5ee 100644
--- a/site_login/public/css/styles.min.css
+++ b/site_login/public/css/styles.min.css
@@ -1 +1 @@
-h1{margin-bottom:30px;margin-top:10px}.tab-content{background:#fff;padding-top:20px}.block-padding{padding:0 10px 10px 10px}.block-padding h4{font-weight:600;padding-bottom:2px;border-bottom:1px solid #ccc}.block-padding ul{padding-left:20px}.hipp-control-item{padding-bottom:10px}#sys_message{padding-top:20px}
\ No newline at end of file
+h1{margin-bottom:30px;margin-top:10px}.tab-content{background:#fff;padding-top:20px}.block-padding{padding:0 10px 10px 10px}.block-padding h4{font-weight:600;padding-bottom:2px;border-bottom:1px solid #ccc}.block-padding ul{padding-left:20px}.hipp-control-item{padding-bottom:10px}#sys_message{padding-top:20px}.position-static{position:static}
\ No newline at end of file
diff --git a/site_login/public/js/script.min.js b/site_login/public/js/script.min.js
index 8ced848..dc971fc 100644
--- a/site_login/public/js/script.min.js
+++ b/site_login/public/js/script.min.js
@@ -1 +1 @@
-jQuery(document).ready(function(){settings={message:"This value is not valid.",container:"tooltip",submitButtons:'button[type="submit"]',feedbackIcons:{valid:"fa fa-check-square",invalid:"fa fa-minus-square",validating:"fa fa-refresh"}},settings_field_username={username:{validators:{notEmpty:{message:"Your email address doesn't appear valid!"},emailAddress:{message:"The is not a valid email address."}}}},settings_field_password_login={password:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."}}}},settings_field_password={password1:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."},identical:{field:"password2",message:"Your passwords do not match!"}}}},settings_field_password2={password2:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."},identical:{field:"password1",message:"Your passwords do not match!"}}}},settings_field_account_password={password1:{message:"Your password is not valid",validators:{stringLength:{min:6,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."}}}},settings_field_account_password2={password2:{message:"Your password is not valid",validators:{stringLength:{min:6,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."},identical:{field:"password1",message:"Your passwords do not match!"}}}},settings_field_first_name={fname:{message:"The first name is not valid.",validators:{notEmpty:{message:"The first name is required and cannot be empty."},stringLength:{min:2,max:30,message:"The first name must be more than 2 and less than 30 characters long."}}}},settings_field_last_name={lname:{message:"The last name is not valid",validators:{notEmpty:{message:"The last name is required and cannot be empty."},stringLength:{min:2,max:30,message:"The last name must be more than 2 and less than 30 characters long."}}}},settings_field_agree={agree:{message:"The last name is not valid",validators:{choice:{min:1,max:1,message:"Please agree to Eclipse.org Terms of Use."}}}},settings_changed_employer={changed_employer:{validators:{notEmpty:{message:"You must indicate if you have changed employers in order to save changes to your organization."}}}},settings_field_skill={skill:{message:"The last name is not valid",validators:{between:{min:16,max:16,message:"That is not the right answer!"}}}},settings_field_website={website:{message:"The last name is not valid",validators:{uri:{message:"The website address is not valid"}}}},settings_field_bio={bio:{validators:{stringLength:{max:2e3,message:"The bio must be less than 2000 characters"}}}},settings_field_organization={organization:{validators:{stringLength:{max:255,message:"The organization must be less than 255 characters"}}}},settings_field_jobtitle={jobtitle:{validators:{stringLength:{max:255,message:"The jobtitle must be less than 255 characters"}}}},settings_field_interests={interests:{validators:{stringLength:{max:255,message:"The interests must be less than 255 characters"}}}},settings_field_twitter_handle={twitter_handle:{validators:{stringLength:{max:255,message:"The twitter handle must be less than 255 characters"}}}},settings_field_github={github:{validators:{stringLength:{max:255,message:"The github must be less than 255 characters"}}}},settings_field_country={country:{message:"Please select a country",validators:{notEmpty:{message:"The country is required and cannot be empty."},stringLength:{min:2,max:2,message:"The country must be 2 characters long."}}}},settings_field_gender={gender:{message:"The gender is not valid",validators:{choice:{min:1,max:1,message:"Please select a gender."}}}},form={fields:{}};frm_passwd_fields=form,$.extend(frm_passwd_fields.fields,settings_field_username),frm_login_settings=$.extend({},settings,frm_passwd_fields),$("#frm_passwd").bootstrapValidator(frm_login_settings);frm_create_account_fields=form,$.extend(frm_create_account_fields.fields,settings_field_gender,settings_field_country,settings_field_username,settings_field_password,settings_field_password2,settings_field_first_name,settings_field_last_name,settings_field_agree,settings_field_skill),frm_login_settings=$.extend({},settings,frm_create_account_fields),$("#frm_create_account").bootstrapValidator(frm_login_settings);frm_create_account_fields=form,$.extend(frm_create_account_fields.fields,settings_field_username,settings_changed_employer,settings_field_password_login,settings_field_account_password,settings_field_account_password2,settings_field_first_name,settings_field_last_name,settings_field_github),frm_login_settings=$.extend({},settings,frm_create_account_fields),$("#frm_accountsettings").bootstrapValidator(frm_login_settings);frm_profile_fields=form,$.extend(frm_profile_fields.fields,settings_field_gender,settings_field_country,settings_field_website,settings_field_bio,settings_changed_employer,settings_field_organization,settings_field_jobtitle,settings_field_interests,settings_field_twitter_handle),frm_login_settings=$.extend({},settings,frm_profile_fields),$("#frm_profile").bootstrapValidator(frm_login_settings)}),function($,document){$(document).on("shown.bs.tab",function(e){function subscription_form(){$("#subscription-form-submit").click(function(){var text=$(this).text().toLowerCase();$(this).html('<i class="fa fa-spinner fa-pulse"></i> '+text);var posting=$.post(url,{form_name:"mailchimp_form",stage:"mailchimp_"+text});posting.done(function(data){$(target_id).html(data).addClass("loaded"),subscription_form()})})}var target_id=$(e.target).attr("href");if("tab-subscriptions"==$(e.target).attr("id")&&$(target_id).attr("class").indexOf("loaded")<=0){var url=$(e.target).attr("data-url");(url.startsWith("https://dev.eclipse.org")||url.startsWith("https://dev.eclipse.local"))&&$.get(url,function(data){$(target_id).html(data).addClass("loaded"),subscription_form()})}})}(jQuery,document);
\ No newline at end of file
+jQuery(document).ready(function(){settings={message:"This value is not valid.",container:"tooltip",submitButtons:'button[type="submit"]',feedbackIcons:{valid:"fa fa-check-square",invalid:"fa fa-minus-square",validating:"fa fa-refresh"}},settings_field_username={username:{validators:{notEmpty:{message:"Your email address doesn't appear valid!"},emailAddress:{message:"The is not a valid email address."}}}},settings_field_password_login={password:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."}}}},settings_field_password={password1:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."},identical:{field:"password2",message:"Your passwords do not match!"}}}},settings_field_password2={password2:{message:"Your password is not valid",validators:{notEmpty:{message:"The password field is required and cannot be empty."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple. It must be at least 6 characters, contain one character and one number."},identical:{field:"password1",message:"Your passwords do not match!"}}}},settings_field_account_password={password1:{message:"Your password is not valid",validators:{stringLength:{min:6,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."},regexp:{regexp:/(?=^.{6,}$)(?=.*[\d|\W])(?=.*[A-Za-z]).*$/,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."}}}},settings_field_account_password2={password2:{message:"Your password is not valid",validators:{stringLength:{min:6,message:"Your password is too simple.  It must be at least 6 characters, contain one character and one number."},identical:{field:"password1",message:"Your passwords do not match!"}}}},settings_field_first_name={fname:{message:"The first name is not valid.",validators:{notEmpty:{message:"The first name is required and cannot be empty."},stringLength:{min:2,max:30,message:"The first name must be more than 2 and less than 30 characters long."}}}},settings_field_last_name={lname:{message:"The last name is not valid",validators:{notEmpty:{message:"The last name is required and cannot be empty."},stringLength:{min:2,max:30,message:"The last name must be more than 2 and less than 30 characters long."}}}},settings_field_agree={agree:{message:"The last name is not valid",validators:{choice:{min:1,max:1,message:"Please agree to Eclipse.org Terms of Use."}}}},settings_changed_employer={changed_employer:{validators:{notEmpty:{message:"You must indicate if you have changed employers in order to save changes to your organization."}}}},settings_field_skill={skill:{message:"The last name is not valid",validators:{between:{min:16,max:16,message:"That is not the right answer!"}}}},settings_field_website={website:{message:"The last name is not valid",validators:{uri:{message:"The website address is not valid"}}}},settings_field_bio={bio:{validators:{stringLength:{max:2e3,message:"The bio must be less than 2000 characters"}}}},settings_field_organization={organization:{validators:{stringLength:{max:255,message:"The organization must be less than 255 characters"}}}},settings_field_jobtitle={jobtitle:{validators:{stringLength:{max:255,message:"The jobtitle must be less than 255 characters"}}}},settings_field_interests={interests:{validators:{stringLength:{max:255,message:"The interests must be less than 255 characters"}}}},settings_field_twitter_handle={twitter_handle:{validators:{stringLength:{max:255,message:"The twitter handle must be less than 255 characters"}}}},settings_field_github={github:{validators:{stringLength:{max:255,message:"The github must be less than 255 characters"}}}},settings_field_country={country:{message:"Please select a country",validators:{notEmpty:{message:"The country is required and cannot be empty."},stringLength:{min:2,max:2,message:"The country must be 2 characters long."}}}},settings_field_gender={gender:{message:"The gender is not valid",validators:{choice:{min:1,max:1,message:"Please select a gender."}}}},settings_field_cla_question_1={question_1:{message:"Question 1 is not valid",validators:{choice:{min:1,max:1,message:"You must accept Question 1."}}}},settings_field_cla_question_2={question_2:{message:"Question 2 is not valid",validators:{choice:{min:1,max:1,message:"You must accept Question 2."}}}},settings_field_cla_question_3={question_3:{message:"Question 3 is not valid",validators:{choice:{min:1,max:1,message:"You must accept Question 3."}}}},settings_field_cla_question_4={question_4:{message:"Question 4 is not valid",validators:{choice:{min:1,max:1,message:"You must accept Question 4."}}}},settings_field_cla_agree={agree:{validators:{notEmpty:{message:'You must enter "I AGREE" in the Electronic Signature field.'},stringLength:{min:7,max:7,message:'You must enter "I AGREE" in the Electronic Signature field.'}}}},settings_field_cla_employer={employer:{validators:{notEmpty:{message:"You must enter your Employer."}}}},settings_field_cla_address={address:{validators:{notEmpty:{message:"You must enter your Address."}}}},form={fields:{}};frm_passwd_fields=form,$.extend(frm_passwd_fields.fields,settings_field_username),frm_login_settings=$.extend({},settings,frm_passwd_fields),$("#frm_passwd").bootstrapValidator(frm_login_settings);frm_create_account_fields=form,$.extend(frm_create_account_fields.fields,settings_field_gender,settings_field_country,settings_field_username,settings_field_password,settings_field_password2,settings_field_first_name,settings_field_last_name,settings_field_agree,settings_field_skill),frm_login_settings=$.extend({},settings,frm_create_account_fields),$("#frm_create_account").bootstrapValidator(frm_login_settings);frm_create_account_fields=form,$.extend(frm_create_account_fields.fields,settings_field_username,settings_changed_employer,settings_field_password_login,settings_field_account_password,settings_field_account_password2,settings_field_first_name,settings_field_last_name,settings_field_github),frm_login_settings=$.extend({},settings,frm_create_account_fields),$("#frm_accountsettings").bootstrapValidator(frm_login_settings);frm_profile_fields=form,$.extend(frm_profile_fields.fields,settings_field_gender,settings_field_country,settings_field_website,settings_field_bio,settings_changed_employer,settings_field_organization,settings_field_jobtitle,settings_field_interests,settings_field_twitter_handle),frm_login_settings=$.extend({},settings,frm_profile_fields),$("#frm_profile").bootstrapValidator(frm_login_settings);frm_cla_fields=form,$.extend(frm_cla_fields.fields,settings_field_cla_question_1,settings_field_cla_question_2,settings_field_cla_question_3,settings_field_cla_question_4,settings_field_cla_agree,settings_field_cla_employer,settings_field_cla_address),frm_cla_settings=$.extend({},settings,frm_cla_fields),$("#frm_cla").bootstrapValidator(frm_cla_settings)}),function($,document){$(document).on("shown.bs.tab",function(e){function subscription_form(){$("#subscription-form-submit").click(function(){var text=$(this).text().toLowerCase();$(this).html('<i class="fa fa-spinner fa-pulse"></i> '+text);var posting=$.post(url,{form_name:"mailchimp_form",stage:"mailchimp_"+text});posting.done(function(data){$(target_id).html(data).addClass("loaded"),subscription_form()})})}var target_id=$(e.target).attr("href");if("tab-subscriptions"==$(e.target).attr("id")&&$(target_id).attr("class").indexOf("loaded")<=0){var url=$(e.target).attr("data-url");(url.startsWith("https://dev.eclipse.org")||url.startsWith("https://dev.eclipse.local"))&&$.get(url,function(data){$(target_id).html(data).addClass("loaded"),subscription_form()})}})}(jQuery,document);
\ No newline at end of file
diff --git a/site_login/src/js/validation.jquery.js b/site_login/src/js/validation.jquery.js
index b84d7bf..da5eb86 100644
--- a/site_login/src/js/validation.jquery.js
+++ b/site_login/src/js/validation.jquery.js
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014-2015 Eclipse Foundation and others.
+ * Copyright (c) 2014-2016 Eclipse Foundation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
  * 
  * Contributors:
  *    Christopher Guindon (Eclipse Foundation)
+ *    Eric Poirier (Eclipse Foundation)
  *******************************************************************************/
 jQuery(document).ready(function() {
     settings = {
@@ -290,6 +291,93 @@
             }
         }
     }
+    
+    settings_field_cla_question_1 = {
+        question_1: {
+            message: 'Question 1 is not valid',
+            validators: {
+                choice: {
+                    min: 1,
+                    max: 1,
+                    message: 'You must accept Question 1.'
+                }
+            }
+        }
+    }
+    
+    settings_field_cla_question_2 = {
+        question_2: {
+            message: 'Question 2 is not valid',
+            validators: {
+                choice: {
+                    min: 1,
+                    max: 1,
+                    message: 'You must accept Question 2.'
+                }
+            }
+        }
+    }
+    
+    settings_field_cla_question_3 = {
+        question_3: {
+            message: 'Question 3 is not valid',
+            validators: {
+                choice: {
+                    min: 1,
+                    max: 1,
+                    message: 'You must accept Question 3.'
+                }
+            }
+        }
+    }
+    
+    settings_field_cla_question_4 = {
+        question_4: {
+            message: 'Question 4 is not valid',
+            validators: {
+                choice: {
+                    min: 1,
+                    max: 1,
+                    message: 'You must accept Question 4.'
+                }
+            }
+        }
+    }
+    
+    settings_field_cla_agree = {
+        agree: {
+            validators: {
+                notEmpty: {
+                    message: 'You must enter "I AGREE" in the Electronic Signature field.'
+                },
+                stringLength: {
+                    min: 7,
+                    max: 7,
+                    message: 'You must enter "I AGREE" in the Electronic Signature field.'
+                }
+            }
+        }
+    }
+    
+    settings_field_cla_employer = {
+        employer: {
+            validators: {
+                notEmpty: {
+                    message: 'You must enter your Employer.'
+                },
+            }
+        }
+    }
+    
+    settings_field_cla_address = {
+        address: {
+            validators: {
+                notEmpty: {
+                    message: 'You must enter your Address.'
+                },
+            }
+        }
+    }
 
     form = {
         fields: {}
@@ -320,5 +408,11 @@
     $.extend(frm_profile_fields.fields, settings_field_gender, settings_field_country, settings_field_website, settings_field_bio, settings_changed_employer, settings_field_organization, settings_field_jobtitle, settings_field_interests, settings_field_twitter_handle);
     frm_login_settings = $.extend({}, settings, frm_profile_fields);
     $('#frm_profile').bootstrapValidator(frm_login_settings);
+    
+    var frm_login_fields = {};
+    frm_cla_fields = form;
+    $.extend(frm_cla_fields.fields, settings_field_cla_question_1, settings_field_cla_question_2, settings_field_cla_question_3, settings_field_cla_question_4, settings_field_cla_agree, settings_field_cla_employer, settings_field_cla_address);
+    frm_cla_settings = $.extend({}, settings, frm_cla_fields);
+    $('#frm_cla').bootstrapValidator(frm_cla_settings);
 
 });
\ No newline at end of file
diff --git a/site_login/src/less/styles.less b/site_login/src/less/styles.less
index 2e563dd..693664f 100644
--- a/site_login/src/less/styles.less
+++ b/site_login/src/less/styles.less
@@ -30,4 +30,8 @@
 
 #sys_message{
   padding-top:20px;
+}
+
+.position-static{
+  position:static;
 }
\ No newline at end of file