make saml idp expiration configurable
diff --git a/src/com/google/enterprise/adaptor/Config.java b/src/com/google/enterprise/adaptor/Config.java
index d993f83..5203931 100644
--- a/src/com/google/enterprise/adaptor/Config.java
+++ b/src/com/google/enterprise/adaptor/Config.java
@@ -148,6 +148,8 @@
  *     and modify principals as described. Defaults no modifications
  * <tr><td> </td><td>transform.pipeline </td><td> sequence of
  *     transformation steps.  Defaults to no-pipeline
+ * <tr><td> </td><td>saml.idpExpirationMillis </td><td> Expiration time
+ *     sent in SAML Authentication response. Defaults to 30,000 milliseconds.
  * </table>
  */
 public class Config {
@@ -265,6 +267,7 @@
           }
         });
     addKey("adaptor.markAllDocsAsPublic", "false");
+    addKey("saml.idpExpirationMillis", "30000");
   }
 
   public Set<String> getAllKeys() {
@@ -613,6 +616,10 @@
     return getValue("gsa.scoringType");
   }
 
+  int getSamlIdpExpirationMillis() {
+    return Integer.parseInt(getValue("saml.idpExpirationMillis"));
+  }
+
   /**
    * Load user-provided configuration file.
    */
diff --git a/src/com/google/enterprise/adaptor/GsaCommunicationHandler.java b/src/com/google/enterprise/adaptor/GsaCommunicationHandler.java
index 6b9a16d..f5168a7 100644
--- a/src/com/google/enterprise/adaptor/GsaCommunicationHandler.java
+++ b/src/com/google/enterprise/adaptor/GsaCommunicationHandler.java
@@ -262,7 +262,8 @@
       if (adaptorContext.authnAuthority != null) {
         log.config("Adaptor-based authentication supported");
         SamlIdentityProvider samlIdentityProvider = new SamlIdentityProvider(
-            adaptorContext.authnAuthority, metadata, keyPair);
+            adaptorContext.authnAuthority, metadata, keyPair,
+            config.getSamlIdpExpirationMillis());
         addFilters(scope.createContext("/samlip",
             samlIdentityProvider.getSingleSignOnHandler()));
       } else {
diff --git a/src/com/google/enterprise/adaptor/SamlIdentityProvider.java b/src/com/google/enterprise/adaptor/SamlIdentityProvider.java
index c6a6957..1c4fcb1 100644
--- a/src/com/google/enterprise/adaptor/SamlIdentityProvider.java
+++ b/src/com/google/enterprise/adaptor/SamlIdentityProvider.java
@@ -104,9 +104,10 @@
   private final Credential cred;
   private final SamlMetadata metadata;
   private final SsoHandler ssoHandler = new SsoHandler();
+  private final int expirationMillis;
 
   public SamlIdentityProvider(AuthnAuthority adaptor, SamlMetadata metadata,
-      KeyPair key) {
+      KeyPair key, int expirationMilliseconds) {
     if (adaptor == null || metadata == null) {
       throw new NullPointerException();
     }
@@ -114,6 +115,10 @@
     this.metadata = metadata;
     this.cred = (key == null) ? null
         : SecurityHelper.getSimpleCredential(key.getPublic(), key.getPrivate());
+    if (expirationMilliseconds <= 0) {
+      throw new IllegalArgumentException("expiration needs to be positive"); 
+    }
+    this.expirationMillis = expirationMilliseconds;
   }
 
   public void respond(HttpExchange ex,
@@ -149,8 +154,8 @@
     String inResponseTo = context.getInboundSAMLMessage().getID();
     String issuer = context.getLocalEntityId();
     DateTime now = new DateTime();
-    // Expiration time is 30 seconds in the future.
-    DateTime expirationTime = now.plusMillis(30 * 1000);
+    // Expiration time in the future.
+    DateTime expirationTime = now.plusMillis(expirationMillis);
 
     if (identity == null) {
       return makeResponse(issuer, now,
diff --git a/test/com/google/enterprise/adaptor/SamlIdentityProviderTest.java b/test/com/google/enterprise/adaptor/SamlIdentityProviderTest.java
index 188a103..f657f73 100644
--- a/test/com/google/enterprise/adaptor/SamlIdentityProviderTest.java
+++ b/test/com/google/enterprise/adaptor/SamlIdentityProviderTest.java
@@ -49,7 +49,7 @@
       "group1", "group2"));
   private AuthnAuthority adaptor = new AuthnAuthorityImpl();
   private SamlIdentityProvider identityProvider = new SamlIdentityProvider(
-      adaptor, metadata, null);
+      adaptor, metadata, null, 30000);
   private MockHttpContext httpContext = new MockHttpsContext(null, "/samlip");
 
   @BeforeClass
@@ -60,13 +60,25 @@
   @Test
   public void testNullAdaptor() {
     thrown.expect(NullPointerException.class);
-    new SamlIdentityProvider(null, metadata, null);
+    new SamlIdentityProvider(null, metadata, null, 30000);
   }
 
   @Test
   public void testNullMetadata() {
     thrown.expect(NullPointerException.class);
-    new SamlIdentityProvider(adaptor, null, null);
+    new SamlIdentityProvider(adaptor, null, null, 30000);
+  }
+
+  @Test
+  public void testNegativeExpiration() {
+    thrown.expect(IllegalArgumentException.class);
+    new SamlIdentityProvider(adaptor, metadata, null, -5);
+  }
+
+  @Test
+  public void testZeroExpiration() {
+    thrown.expect(IllegalArgumentException.class);
+    new SamlIdentityProvider(adaptor, metadata, null, 0);
   }
 
   @Test