diff --git a/openid-connect-client/pom.xml b/openid-connect-client/pom.xml index 25903b93c..6ce1e7c6d 100644 --- a/openid-connect-client/pom.xml +++ b/openid-connect-client/pom.xml @@ -22,7 +22,7 @@ openid-connect-parent org.mitre - 1.3.5.cnaf + 1.3.5.cnaf-SNAPSHOT .. openid-connect-client diff --git a/openid-connect-common/pom.xml b/openid-connect-common/pom.xml index f90290212..184451c64 100644 --- a/openid-connect-common/pom.xml +++ b/openid-connect-common/pom.xml @@ -22,7 +22,7 @@ openid-connect-parent org.mitre - 1.3.5.cnaf + 1.3.5.cnaf-SNAPSHOT .. openid-connect-common diff --git a/openid-connect-common/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java b/openid-connect-common/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java index 032d4ea94..e1698a55f 100644 --- a/openid-connect-common/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java +++ b/openid-connect-common/src/main/java/org/mitre/oauth2/model/SavedUserAuthentication.java @@ -54,7 +54,7 @@ public class SavedUserAuthentication implements Authentication { private String name; - private Collection authorities; + private Collection authorities; private boolean authenticated; @@ -117,7 +117,7 @@ public class SavedUserAuthentication implements Authentication { joinColumns = @JoinColumn(name = "owner_id") ) @Convert(converter = SimpleGrantedAuthorityStringConverter.class) @Column(name = "authority") - public Collection getAuthorities() { + public Collection getAuthorities() { return authorities; } diff --git a/openid-connect-server-webapp/.gitignore b/openid-connect-server-webapp/.gitignore new file mode 100644 index 000000000..016a3b8f8 --- /dev/null +++ b/openid-connect-server-webapp/.gitignore @@ -0,0 +1,12 @@ +local-values.conf +target +*~ +bin +*.idea +*.iml +*.eml +.project +.settings +.classpath +/target +.springBeans diff --git a/openid-connect-server-webapp/pom.xml b/openid-connect-server-webapp/pom.xml new file mode 100644 index 000000000..9a4c45bc3 --- /dev/null +++ b/openid-connect-server-webapp/pom.xml @@ -0,0 +1,152 @@ + + + + 4.0.0 + + org.mitre + openid-connect-parent + 1.3.3-SNAPSHOT + + openid-connect-server-webapp + war + OpenID Connect Server Webapp + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java-version} + ${java-version} + + + + org.apache.maven.plugins + maven-war-plugin + + openid-connect-server-webapp + + + src/main/webapp + true + + **/*.tag + **/*.jsp + + + + src/main/webapp + false + + **/*.tag + **/*.jsp + + + + less/** + + + + org.apache.maven.plugins + maven-dependency-plugin + + + install + install + + sources + + + + + + org.eclipse.jetty + jetty-maven-plugin + + ${project.build.directory}/openid-connect-server-webapp.war + + /openid-connect-server-webapp + + + + + ro.isdc.wro4j + wro4j-maven-plugin + + bootstrap,bootstrap-responsive + ${project.build.directory}/${project.build.finalName} + ${project.build.directory}/${project.build.finalName}/resources/bootstrap2/css/ + ${project.build.directory}/${project.build.finalName}/js/ + ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory + + + + + + + + org.mitre + openid-connect-server + + + org.springframework + spring-orm + + + commons-logging + commons-logging + + + + + org.slf4j + jcl-over-slf4j + + + org.slf4j + slf4j-log4j12 + + + log4j + log4j + + + org.hsqldb + hsqldb + + + org.eclipse.persistence + org.eclipse.persistence.jpa + + + org.springframework.security + spring-security-taglibs + + + javax.servlet + jstl + + + + com.zaxxer + HikariCP + + + Deployable package of the OpenID Connect server + diff --git a/openid-connect-server-webapp/pom.xml.versionsBackup b/openid-connect-server-webapp/pom.xml.versionsBackup new file mode 100644 index 000000000..3053bf020 --- /dev/null +++ b/openid-connect-server-webapp/pom.xml.versionsBackup @@ -0,0 +1,137 @@ + + + + 4.0.0 + + org.mitre + openid-connect-parent + 1.2.7-SNAPSHOT + + openid-connect-server-webapp + war + OpenID Connect Server Webapp + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java-version} + ${java-version} + + + + org.apache.maven.plugins + maven-war-plugin + + openid-connect-server-webapp + + + src/main/webapp + true + + **/*.tag + **/*.jsp + + + + src/main/webapp + false + + **/*.tag + **/*.jsp + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + install + install + + sources + + + + + + org.eclipse.jetty + jetty-maven-plugin + + ${project.build.directory}/openid-connect-server-webapp.war + + /openid-connect-server-webapp + + + + + + + + org.mitre + openid-connect-server + + + org.springframework + spring-orm + + + commons-logging + commons-logging + + + + + org.slf4j + jcl-over-slf4j + + + org.slf4j + slf4j-log4j12 + + + log4j + log4j + + + org.hsqldb + hsqldb + + + org.eclipse.persistence + org.eclipse.persistence.jpa + + + org.springframework.security + spring-security-taglibs + + + javax.servlet + jstl + + + + com.zaxxer + HikariCP + + + diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/clients.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/clients.sql new file mode 100644 index 000000000..1410f7bd1 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/clients.sql @@ -0,0 +1,70 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT FALSE; + +START TRANSACTION; + +-- +-- Insert client information into the temporary tables. To add clients to the HSQL database, edit things here. +-- + +INSERT INTO client_details_TEMP (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES + ('client', 'secret', 'Test Client', false, null, 3600, 600, true); + +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES + ('client', 'openid'), + ('client', 'profile'), + ('client', 'email'), + ('client', 'address'), + ('client', 'phone'), + ('client', 'offline_access'); + +INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES + ('client', 'http://localhost/'), + ('client', 'http://localhost:8080/'); + +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES + ('client', 'authorization_code'), + ('client', 'urn:ietf:params:oauth:grant_type:redelegate'), + ('client', 'urn:ietf:params:oauth:grant-type:device_code'), + ('client', 'implicit'), + ('client', 'refresh_token'); + +-- +-- Merge the temporary clients safely into the database. This is a two-step process to keep clients from being created on every startup with a persistent store. +-- + +MERGE INTO client_details + USING (SELECT client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection FROM client_details_TEMP) AS vals(client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) + ON vals.client_id = client_details.client_id + WHEN NOT MATCHED THEN + INSERT (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES(client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection); + +MERGE INTO client_scope + USING (SELECT id, scope FROM client_scope_TEMP, client_details WHERE client_details.client_id = client_scope_TEMP.owner_id) AS vals(id, scope) + ON vals.id = client_scope.owner_id AND vals.scope = client_scope.scope + WHEN NOT MATCHED THEN + INSERT (owner_id, scope) values (vals.id, vals.scope); + +MERGE INTO client_redirect_uri + USING (SELECT id, redirect_uri FROM client_redirect_uri_TEMP, client_details WHERE client_details.client_id = client_redirect_uri_TEMP.owner_id) AS vals(id, redirect_uri) + ON vals.id = client_redirect_uri.owner_id AND vals.redirect_uri = client_redirect_uri.redirect_uri + WHEN NOT MATCHED THEN + INSERT (owner_id, redirect_uri) values (vals.id, vals.redirect_uri); + +MERGE INTO client_grant_type + USING (SELECT id, grant_type FROM client_grant_type_TEMP, client_details WHERE client_details.client_id = client_grant_type_TEMP.owner_id) AS vals(id, grant_type) + ON vals.id = client_grant_type.owner_id AND vals.grant_type = client_grant_type.grant_type + WHEN NOT MATCHED THEN + INSERT (owner_id, grant_type) values (vals.id, vals.grant_type); + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +SET AUTOCOMMIT TRUE; + diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql new file mode 100644 index 000000000..38636a96f --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_index.sql @@ -0,0 +1,19 @@ +-- +-- Indexes for HSQLDB +-- + +CREATE INDEX IF NOT EXISTS at_tv_idx ON access_token(token_value); +CREATE INDEX IF NOT EXISTS ts_oi_idx ON token_scope(owner_id); +CREATE INDEX IF NOT EXISTS at_exp_idx ON access_token(expiration); +CREATE INDEX IF NOT EXISTS rf_ahi_idx ON refresh_token(auth_holder_id); +CREATE INDEX IF NOT EXISTS rf_tv_idx ON refresh_token(token_value); +CREATE INDEX IF NOT EXISTS cd_ci_idx ON client_details(client_id); +CREATE INDEX IF NOT EXISTS at_ahi_idx ON access_token(auth_holder_id); +CREATE INDEX IF NOT EXISTS aha_oi_idx ON authentication_holder_authority(owner_id); +CREATE INDEX IF NOT EXISTS ahe_oi_idx ON authentication_holder_extension(owner_id); +CREATE INDEX IF NOT EXISTS ahrp_oi_idx ON authentication_holder_request_parameter(owner_id); +CREATE INDEX IF NOT EXISTS ahri_oi_idx ON authentication_holder_resource_id(owner_id); +CREATE INDEX IF NOT EXISTS ahrt_oi_idx ON authentication_holder_response_type(owner_id); +CREATE INDEX IF NOT EXISTS ahs_oi_idx ON authentication_holder_scope(owner_id); +CREATE INDEX IF NOT EXISTS ac_ahi_idx ON authorization_code(auth_holder_id); +CREATE INDEX IF NOT EXISTS suaa_oi_idx ON saved_user_auth_authority(owner_id); diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql new file mode 100644 index 000000000..2a0175629 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql @@ -0,0 +1,384 @@ +-- +-- Tables for OIDC Server functionality, HSQL +-- + +CREATE TABLE IF NOT EXISTS access_token ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + token_type VARCHAR(256), + refresh_token_id BIGINT, + client_id BIGINT, + auth_holder_id BIGINT, + approved_site_id BIGINT, + UNIQUE(token_value) +); + +CREATE TABLE IF NOT EXISTS access_token_permissions ( + access_token_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS address ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + formatted VARCHAR(256), + street_address VARCHAR(256), + locality VARCHAR(256), + region VARCHAR(256), + postal_code VARCHAR(256), + country VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS approved_site ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + user_id VARCHAR(256), + client_id VARCHAR(256), + creation_date TIMESTAMP, + access_date TIMESTAMP, + timeout_date TIMESTAMP, + whitelisted_site_id BIGINT +); + +CREATE TABLE IF NOT EXISTS approved_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + user_auth_id BIGINT, + approved BOOLEAN, + redirect_uri VARCHAR(2048), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_resource_id ( + owner_id BIGINT, + resource_id VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_response_type ( + owner_id BIGINT, + response_type VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_extension ( + owner_id BIGINT, + extension VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + name VARCHAR(1024), + authenticated BOOLEAN, + source_class VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authorization_code ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + code VARCHAR(256), + auth_holder_id BIGINT, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS client_grant_type ( + owner_id BIGINT, + grant_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_response_type ( + owner_id BIGINT, + response_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS blacklisted_site ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_details ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + + client_description VARCHAR(1024), + reuse_refresh_tokens BOOLEAN DEFAULT true NOT NULL, + dynamically_registered BOOLEAN DEFAULT false NOT NULL, + allow_introspection BOOLEAN DEFAULT false NOT NULL, + id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, + device_code_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + + application_type VARCHAR(256), + client_name VARCHAR(256), + token_endpoint_auth_method VARCHAR(256), + subject_type VARCHAR(256), + + logo_uri VARCHAR(2048), + policy_uri VARCHAR(2048), + client_uri VARCHAR(2048), + tos_uri VARCHAR(2048), + + jwks_uri VARCHAR(2048), + jwks VARCHAR(8192), + sector_identifier_uri VARCHAR(2048), + + request_object_signing_alg VARCHAR(256), + + user_info_signed_response_alg VARCHAR(256), + user_info_encrypted_response_alg VARCHAR(256), + user_info_encrypted_response_enc VARCHAR(256), + + id_token_signed_response_alg VARCHAR(256), + id_token_encrypted_response_alg VARCHAR(256), + id_token_encrypted_response_enc VARCHAR(256), + + token_endpoint_auth_signing_alg VARCHAR(256), + + default_max_age BIGINT, + require_auth_time BOOLEAN, + created_at TIMESTAMP, + initiate_login_uri VARCHAR(2048), + clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL, + + software_statement VARCHAR(4096), + software_id VARCHAR(2048), + software_version VARCHAR(2048), + + code_challenge_method VARCHAR(256), + + UNIQUE (client_id) +); + +CREATE TABLE IF NOT EXISTS client_request_uri ( + owner_id BIGINT, + request_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_post_logout_redirect_uri ( + owner_id BIGINT, + post_logout_redirect_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_default_acr_value ( + owner_id BIGINT, + default_acr_value VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_contact ( + owner_id BIGINT, + contact VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_claims_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS refresh_token ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + auth_holder_id BIGINT, + client_id BIGINT +); + +CREATE TABLE IF NOT EXISTS client_resource ( + owner_id BIGINT, + resource_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS token_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS system_scope ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + scope VARCHAR(256) NOT NULL, + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN DEFAULT false NOT NULL, + default_scope BOOLEAN DEFAULT false NOT NULL, + UNIQUE (scope) +); + +CREATE TABLE IF NOT EXISTS user_info ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + sub VARCHAR(256), + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + phone_number_verified BOOLEAN, + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256), + src VARCHAR(4096) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + creator_user_id VARCHAR(256), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS pairwise_identifier ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + identifier VARCHAR(256), + sub VARCHAR(256), + sector_identifier VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS resource_set ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + name VARCHAR(1024) NOT NULL, + uri VARCHAR(1024), + icon_uri VARCHAR(1024), + rs_type VARCHAR(256), + owner VARCHAR(256) NOT NULL, + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS resource_set_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission_ticket ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + ticket VARCHAR(256) NOT NULL, + permission_id BIGINT NOT NULL, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS permission ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS permission_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + name VARCHAR(256), + friendly_name VARCHAR(1024), + claim_type VARCHAR(1024), + claim_value VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_to_policy ( + policy_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_to_permission_ticket ( + permission_ticket_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS policy ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + name VARCHAR(1024), + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS policy_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_token_format ( + owner_id BIGINT NOT NULL, + claim_token_format VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_issuer ( + owner_id BIGINT NOT NULL, + issuer VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS saved_registered_client ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + issuer VARCHAR(1024), + registered_client VARCHAR(8192) +); + +CREATE TABLE IF NOT EXISTS device_code ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, + device_code VARCHAR(1024), + user_code VARCHAR(1024), + expiration TIMESTAMP, + client_id VARCHAR(256), + approved BOOLEAN, + auth_holder_id BIGINT +); + +CREATE TABLE IF NOT EXISTS device_code_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS device_code_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql new file mode 100644 index 000000000..37b0092e7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/loading_temp_tables.sql @@ -0,0 +1,73 @@ +-- +-- Temporary tables used during the bootstrapping process to safely load users and clients. +-- These are not needed if you're not using the users.sql/clients.sql files to bootstrap the database. +-- + +CREATE TEMPORARY TABLE IF NOT EXISTS authorities_TEMP ( + username varchar(50) not null, + authority varchar(50) not null, + constraint ix_authority_TEMP unique (username,authority)); + +CREATE TEMPORARY TABLE IF NOT EXISTS users_TEMP ( + username varchar(50) not null primary key, + password varchar(50) not null, + enabled boolean not null); + +CREATE TEMPORARY TABLE IF NOT EXISTS user_info_TEMP ( + sub VARCHAR(256) not null primary key, + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_details_TEMP ( + client_description VARCHAR(256), + dynamically_registered BOOLEAN, + id_token_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + allow_introspection BOOLEAN, + + client_name VARCHAR(256) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_scope_TEMP ( + owner_id VARCHAR(256), + scope VARCHAR(2048) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_redirect_uri_TEMP ( + owner_id VARCHAR(256), + redirect_uri VARCHAR(2048) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS client_grant_type_TEMP ( + owner_id VARCHAR(256), + grant_type VARCHAR(2000) +); + +CREATE TEMPORARY TABLE IF NOT EXISTS system_scope_TEMP ( + scope VARCHAR(256), + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN, + default_scope BOOLEAN +); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/scopes.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/scopes.sql new file mode 100644 index 000000000..8e72c88c7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/scopes.sql @@ -0,0 +1,33 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT FALSE; + +START TRANSACTION; + +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', false, true), + ('profile', 'basic profile information', 'list-alt', false, true), + ('email', 'email address', 'envelope', false, true), + ('address', 'physical address', 'home', false, true), + ('phone', 'telephone number', 'bell', false, true), + ('offline_access', 'offline access', 'time', false, false); + +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +MERGE INTO system_scope + USING (SELECT scope, description, icon, restricted, default_scope FROM system_scope_TEMP) AS vals(scope, description, icon, restricted, default_scope) + ON vals.scope = system_scope.scope + WHEN NOT MATCHED THEN + INSERT (scope, description, icon, restricted, default_scope) VALUES(vals.scope, vals.description, vals.icon, vals.restricted, vals.default_scope); + +COMMIT; + +SET AUTOCOMMIT TRUE; \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/security-schema.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/security-schema.sql new file mode 100644 index 000000000..bc5d70b88 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/security-schema.sql @@ -0,0 +1,14 @@ +-- +-- Tables for Spring Security's user details service +-- + +create table IF NOT EXISTS users( + username varchar(50) not null primary key, + password varchar(50) not null, + enabled boolean not null); + + create table IF NOT EXISTS authorities ( + username varchar(50) not null, + authority varchar(50) not null, + constraint fk_authorities_users foreign key(username) references users(username), + constraint ix_authority unique (username,authority)); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/users.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/users.sql new file mode 100644 index 000000000..6e6958e1f --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/users.sql @@ -0,0 +1,59 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT FALSE; + +START TRANSACTION; + +-- +-- Insert user information into the temporary tables. To add users to the HSQL database, edit things here. +-- + +INSERT INTO users_TEMP (username, password, enabled) VALUES + ('admin','password',true), + ('user','password',true); + + +INSERT INTO authorities_TEMP (username, authority) VALUES + ('admin','ROLE_ADMIN'), + ('admin','ROLE_USER'), + ('user','ROLE_USER'); + +-- By default, the username column here has to match the username column in the users table, above +INSERT INTO user_info_TEMP (sub, preferred_username, name, email, email_verified) VALUES + ('90342.ASDFJWFA','admin','Demo Admin','admin@example.com', true), + ('01921.FLANRJQW','user','Demo User','user@example.com', true); + + +-- +-- Merge the temporary users safely into the database. This is a two-step process to keep users from being created on every startup with a persistent store. +-- + +MERGE INTO users + USING (SELECT username, password, enabled FROM users_TEMP) AS vals(username, password, enabled) + ON vals.username = users.username + WHEN NOT MATCHED THEN + INSERT (username, password, enabled) VALUES(vals.username, vals.password, vals.enabled); + +MERGE INTO authorities + USING (SELECT username, authority FROM authorities_TEMP) AS vals(username, authority) + ON vals.username = authorities.username AND vals.authority = authorities.authority + WHEN NOT MATCHED THEN + INSERT (username,authority) values (vals.username, vals.authority); + +MERGE INTO user_info + USING (SELECT sub, preferred_username, name, email, email_verified FROM user_info_TEMP) AS vals(sub, preferred_username, name, email, email_verified) + ON vals.preferred_username = user_info.preferred_username + WHEN NOT MATCHED THEN + INSERT (sub, preferred_username, name, email, email_verified) VALUES (vals.sub, vals.preferred_username, vals.name, vals.email, vals.email_verified); + + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +SET AUTOCOMMIT TRUE; + diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/clients.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/clients.sql new file mode 100644 index 000000000..7f0255789 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/clients.sql @@ -0,0 +1,61 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT = 0; + +START TRANSACTION; + +-- +-- Insert client information into the temporary tables. To add clients to the HSQL database, edit things here. +-- + +INSERT INTO client_details_TEMP (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES + ('client', 'secret', 'Test Client', false, null, 3600, 600, true); + +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES + ('client', 'openid'), + ('client', 'profile'), + ('client', 'email'), + ('client', 'address'), + ('client', 'phone'), + ('client', 'offline_access'); + +INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES + ('client', 'http://localhost/'), + ('client', 'http://localhost:8080/'); + +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES + ('client', 'authorization_code'), + ('client', 'urn:ietf:params:oauth:grant_type:redelegate'), + ('client', 'implicit'), + ('client', 'refresh_token'); + +-- +-- Merge the temporary clients safely into the database. This is a two-step process to keep clients from being created on every startup with a persistent store. +-- + +INSERT INTO client_details (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) + SELECT client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection FROM client_details_TEMP + ON DUPLICATE KEY UPDATE client_details.client_id = client_details.client_id; + +INSERT INTO client_scope (owner_id, scope) + SELECT id, scope FROM client_scope_TEMP, client_details WHERE client_details.client_id = client_scope_TEMP.owner_id + ON DUPLICATE KEY UPDATE client_scope.owner_id = client_scope.owner_id; + +INSERT INTO client_redirect_uri (owner_id, redirect_uri) + SELECT id, redirect_uri FROM client_redirect_uri_TEMP, client_details WHERE client_details.client_id = client_redirect_uri_TEMP.owner_id + ON DUPLICATE KEY UPDATE client_redirect_uri.owner_id = client_redirect_uri.owner_id; + +INSERT INTO client_grant_type (owner_id, grant_type) + SELECT id, grant_type FROM client_grant_type_TEMP, client_details WHERE client_details.client_id = client_grant_type_TEMP.owner_id + ON DUPLICATE KEY UPDATE client_grant_type.owner_id = client_grant_type.owner_id; + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +SET AUTOCOMMIT = 1; + diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql new file mode 100644 index 000000000..f5daf991d --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_index.sql @@ -0,0 +1,19 @@ +-- +-- Indexes for MySQL +-- + +CREATE INDEX at_tv_idx ON access_token(token_value(767)); +CREATE INDEX ts_oi_idx ON token_scope(owner_id); +CREATE INDEX at_exp_idx ON access_token(expiration); +CREATE INDEX rf_ahi_idx ON refresh_token(auth_holder_id); +CREATE INDEX rf_tv_idx ON refresh_token(token_value(105)); +CREATE INDEX cd_ci_idx ON client_details(client_id); +CREATE INDEX at_ahi_idx ON access_token(auth_holder_id); +CREATE INDEX aha_oi_idx ON authentication_holder_authority(owner_id); +CREATE INDEX ahe_oi_idx ON authentication_holder_extension(owner_id); +CREATE INDEX ahrp_oi_idx ON authentication_holder_request_parameter(owner_id); +CREATE INDEX ahri_oi_idx ON authentication_holder_resource_id(owner_id); +CREATE INDEX ahrt_oi_idx ON authentication_holder_response_type(owner_id); +CREATE INDEX ahs_oi_idx ON authentication_holder_scope(owner_id); +CREATE INDEX ac_ahi_idx ON authorization_code(auth_holder_id); +CREATE INDEX suaa_oi_idx ON saved_user_auth_authority(owner_id); diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql new file mode 100644 index 000000000..7e00cc876 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql @@ -0,0 +1,383 @@ +-- +-- Tables for OIDC Server functionality, MySQL +-- + +CREATE TABLE IF NOT EXISTS access_token ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP NULL, + token_type VARCHAR(256), + refresh_token_id BIGINT, + client_id BIGINT, + auth_holder_id BIGINT, + approved_site_id BIGINT +); + +CREATE TABLE IF NOT EXISTS access_token_permissions ( + access_token_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS address ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + formatted VARCHAR(256), + street_address VARCHAR(256), + locality VARCHAR(256), + region VARCHAR(256), + postal_code VARCHAR(256), + country VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS approved_site ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id VARCHAR(256), + client_id VARCHAR(256), + creation_date TIMESTAMP NULL, + access_date TIMESTAMP NULL, + timeout_date TIMESTAMP NULL, + whitelisted_site_id BIGINT +); + +CREATE TABLE IF NOT EXISTS approved_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_auth_id BIGINT, + approved BOOLEAN, + redirect_uri VARCHAR(2048), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_resource_id ( + owner_id BIGINT, + resource_id VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_response_type ( + owner_id BIGINT, + response_type VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_extension ( + owner_id BIGINT, + extension VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(1024), + authenticated BOOLEAN, + source_class VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authorization_code ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + code VARCHAR(256), + auth_holder_id BIGINT, + expiration TIMESTAMP NULL +); + +CREATE TABLE IF NOT EXISTS client_grant_type ( + owner_id BIGINT, + grant_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_response_type ( + owner_id BIGINT, + response_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS blacklisted_site ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_details ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + + client_description VARCHAR(1024), + reuse_refresh_tokens BOOLEAN DEFAULT true NOT NULL, + dynamically_registered BOOLEAN DEFAULT false NOT NULL, + allow_introspection BOOLEAN DEFAULT false NOT NULL, + id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, + device_code_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + + application_type VARCHAR(256), + client_name VARCHAR(256), + token_endpoint_auth_method VARCHAR(256), + subject_type VARCHAR(256), + + logo_uri VARCHAR(2048), + policy_uri VARCHAR(2048), + client_uri VARCHAR(2048), + tos_uri VARCHAR(2048), + + jwks_uri VARCHAR(2048), + jwks VARCHAR(8192), + sector_identifier_uri VARCHAR(2048), + + request_object_signing_alg VARCHAR(256), + + user_info_signed_response_alg VARCHAR(256), + user_info_encrypted_response_alg VARCHAR(256), + user_info_encrypted_response_enc VARCHAR(256), + + id_token_signed_response_alg VARCHAR(256), + id_token_encrypted_response_alg VARCHAR(256), + id_token_encrypted_response_enc VARCHAR(256), + + token_endpoint_auth_signing_alg VARCHAR(256), + + default_max_age BIGINT, + require_auth_time BOOLEAN, + created_at TIMESTAMP NULL, + initiate_login_uri VARCHAR(2048), + clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL, + + software_statement VARCHAR(4096), + software_id VARCHAR(2048), + software_version VARCHAR(2048), + + code_challenge_method VARCHAR(256), + + UNIQUE (client_id) +); + +CREATE TABLE IF NOT EXISTS client_request_uri ( + owner_id BIGINT, + request_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_post_logout_redirect_uri ( + owner_id BIGINT, + post_logout_redirect_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_default_acr_value ( + owner_id BIGINT, + default_acr_value VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_contact ( + owner_id BIGINT, + contact VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_claims_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS refresh_token ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP NULL, + auth_holder_id BIGINT, + client_id BIGINT +); + +CREATE TABLE IF NOT EXISTS client_resource ( + owner_id BIGINT, + resource_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS token_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS system_scope ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + scope VARCHAR(256) NOT NULL, + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN DEFAULT false NOT NULL, + default_scope BOOLEAN DEFAULT false NOT NULL, + UNIQUE (scope) +); + +CREATE TABLE IF NOT EXISTS user_info ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + sub VARCHAR(256), + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + phone_number_verified BOOLEAN, + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256), + src VARCHAR(4096) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + creator_user_id VARCHAR(256), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS pairwise_identifier ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + identifier VARCHAR(256), + sub VARCHAR(256), + sector_identifier VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS resource_set ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(1024) NOT NULL, + uri VARCHAR(1024), + icon_uri VARCHAR(1024), + rs_type VARCHAR(256), + owner VARCHAR(256) NOT NULL, + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS resource_set_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission_ticket ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + ticket VARCHAR(256) NOT NULL, + permission_id BIGINT NOT NULL, + expiration TIMESTAMP NULL +); + +CREATE TABLE IF NOT EXISTS permission ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS permission_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(256), + friendly_name VARCHAR(1024), + claim_type VARCHAR(1024), + claim_value VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_to_policy ( + policy_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_to_permission_ticket ( + permission_ticket_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS policy ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(1024), + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS policy_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_token_format ( + owner_id BIGINT NOT NULL, + claim_token_format VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_issuer ( + owner_id BIGINT NOT NULL, + issuer VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS saved_registered_client ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + issuer VARCHAR(1024), + registered_client VARCHAR(8192) +); + +CREATE TABLE IF NOT EXISTS device_code ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + device_code VARCHAR(1024), + user_code VARCHAR(1024), + expiration TIMESTAMP NULL, + client_id VARCHAR(256), + approved BOOLEAN, + auth_holder_id BIGINT +); + +CREATE TABLE IF NOT EXISTS device_code_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS device_code_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/scopes.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/scopes.sql new file mode 100644 index 000000000..3768977ec --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/scopes.sql @@ -0,0 +1,31 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT = 0; + +START TRANSACTION; + +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', false, true), + ('profile', 'basic profile information', 'list-alt', false, true), + ('email', 'email address', 'envelope', false, true), + ('address', 'physical address', 'home', false, true), + ('phone', 'telephone number', 'bell', false, true), + ('offline_access', 'offline access', 'time', false, false); + +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +INSERT INTO system_scope (scope, description, icon, restricted, default_scope, structured, structured_param_description) + SELECT scope, description, icon, restricted, default_scope, structured, structured_param_description FROM system_scope_TEMP + ON DUPLICATE KEY UPDATE system_scope.scope = system_scope.scope; + +COMMIT; + +SET AUTOCOMMIT = 1; diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/security-schema.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/security-schema.sql new file mode 100644 index 000000000..bc5d70b88 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/security-schema.sql @@ -0,0 +1,14 @@ +-- +-- Tables for Spring Security's user details service +-- + +create table IF NOT EXISTS users( + username varchar(50) not null primary key, + password varchar(50) not null, + enabled boolean not null); + + create table IF NOT EXISTS authorities ( + username varchar(50) not null, + authority varchar(50) not null, + constraint fk_authorities_users foreign key(username) references users(username), + constraint ix_authority unique (username,authority)); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/users.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/users.sql new file mode 100644 index 000000000..fc82e4800 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/users.sql @@ -0,0 +1,52 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +SET AUTOCOMMIT = 0; + +START TRANSACTION; + +-- +-- Insert user information into the temporary tables. To add users to the HSQL database, edit things here. +-- + +INSERT INTO users_TEMP (username, password, enabled) VALUES + ('admin','password',true), + ('user','password',true); + + +INSERT INTO authorities_TEMP (username, authority) VALUES + ('admin','ROLE_ADMIN'), + ('admin','ROLE_USER'), + ('user','ROLE_USER'); + +-- By default, the username column here has to match the username column in the users table, above +INSERT INTO user_info_TEMP (sub, preferred_username, name, email, email_verified) VALUES + ('90342.ASDFJWFA','admin','Demo Admin','admin@example.com', true), + ('01921.FLANRJQW','user','Demo User','user@example.com', true); + + +-- +-- Merge the temporary users safely into the database. This is a two-step process to keep users from being created on every startup with a persistent store. +-- + +INSERT INTO users (username, password, enabled) + SELECT username, password, enabled FROM users_TEMP + ON DUPLICATE KEY UPDATE users.username = users.username; + +INSERT INTO authorities (username,authority) + SELECT username, authority FROM authorities_TEMP + ON DUPLICATE KEY UPDATE authorities.username = authorities.username; + +INSERT INTO user_info (sub, preferred_username, name, email, email_verified) + SELECT sub, preferred_username, name, email, email_verified FROM user_info_TEMP + ON DUPLICATE KEY UPDATE user_info.preferred_username = user_info.preferred_username; + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +SET AUTOCOMMIT = 1; + diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/clients_oracle.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/clients_oracle.sql new file mode 100644 index 000000000..488d92845 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/clients_oracle.sql @@ -0,0 +1,51 @@ +-- +-- Insert client information into the temporary tables. To add clients to the Oracle database, edit things here. +-- + +INSERT INTO client_details_TEMP (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES + ('client', 'secret', 'Test Client', 0, null, 3600, 600, 1); + +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'openid'); +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'profile'); +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'email'); +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'address'); +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'phone'); +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES ('client', 'offline_access'); + +INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES ('client', 'http://localhost/'); +INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES ('client', 'http://localhost:8080/'); + +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES ('client', 'authorization_code'); +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES ('client', 'urn:ietf:params:oauth:grant_type:redelegate'); +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES ('client', 'implicit'); +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES ('client', 'refresh_token'); + +-- +-- Merge the temporary clients safely into the database. This is a two-step process to keep clients from being created on every startup with a persistent store. +-- + +MERGE INTO client_details + USING (SELECT client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection FROM client_details_TEMP) vals + ON (vals.client_id = client_details.client_id) + WHEN NOT MATCHED THEN + INSERT (id, client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, + id_token_validity_seconds, allow_introspection) VALUES(client_details_seq.nextval, vals.client_id, vals.client_secret, vals.client_name, vals.dynamically_registered, + vals.refresh_token_validity_seconds, vals.access_token_validity_seconds, vals.id_token_validity_seconds, vals.allow_introspection); + +MERGE INTO client_scope + USING (SELECT id, scope FROM client_scope_TEMP, client_details WHERE client_details.client_id = client_scope_TEMP.owner_id) vals + ON (vals.id = client_scope.owner_id AND vals.scope = client_scope.scope) + WHEN NOT MATCHED THEN + INSERT (owner_id, scope) values (vals.id, vals.scope); + +MERGE INTO client_redirect_uri + USING (SELECT id, redirect_uri FROM client_redirect_uri_TEMP, client_details WHERE client_details.client_id = client_redirect_uri_TEMP.owner_id) vals + ON (vals.id = client_redirect_uri.owner_id AND vals.redirect_uri = client_redirect_uri.redirect_uri) + WHEN NOT MATCHED THEN + INSERT (owner_id, redirect_uri) values (vals.id, vals.redirect_uri); + +MERGE INTO client_grant_type + USING (SELECT id, grant_type FROM client_grant_type_TEMP, client_details WHERE client_details.client_id = client_grant_type_TEMP.owner_id) vals + ON (vals.id = client_grant_type.owner_id AND vals.grant_type = client_grant_type.grant_type) + WHEN NOT MATCHED THEN + INSERT (owner_id, grant_type) values (vals.id, vals.grant_type); diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml b/openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml new file mode 100644 index 000000000..2aba62824 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/entity-mappings_oracle.xml @@ -0,0 +1,281 @@ + + + + OpenID Connect Server entities + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql new file mode 100644 index 000000000..c9a1e7f3d --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/loading_temp_tables_oracle.sql @@ -0,0 +1,77 @@ +-- +-- Temporary tables used during the bootstrapping process to safely load users and clients. +-- These are not needed if you're not using the users.sql/clients.sql files to bootstrap the database. +-- + +CREATE GLOBAL TEMPORARY TABLE authorities_TEMP ( + username varchar2(50) not null, + authority varchar2(50) not null, + constraint ix_authority_TEMP unique (username,authority) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE users_TEMP ( + username VARCHAR2(50) not null primary key, + password VARCHAR2(50) not null, + enabled NUMBER(1) not null +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE user_info_TEMP ( + sub VARCHAR2(256) not null primary key, + preferred_username VARCHAR2(256), + name VARCHAR2(256), + given_name VARCHAR2(256), + family_name VARCHAR2(256), + middle_name VARCHAR2(256), + nickname VARCHAR2(256), + profile VARCHAR2(256), + picture VARCHAR2(256), + website VARCHAR2(256), + email VARCHAR2(256), + email_verified NUMBER(1), + gender VARCHAR2(256), + zone_info VARCHAR2(256), + locale VARCHAR2(256), + phone_number VARCHAR2(256), + address_id VARCHAR2(256), + updated_time VARCHAR2(256), + birthdate VARCHAR2(256) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE client_details_TEMP ( + client_description VARCHAR2(256), + dynamically_registered NUMBER(1), + id_token_validity_seconds NUMBER(19), + + client_id VARCHAR2(256), + client_secret VARCHAR2(2048), + access_token_validity_seconds NUMBER(19), + refresh_token_validity_seconds NUMBER(19), + allow_introspection NUMBER(1), + + client_name VARCHAR2(256) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE client_scope_TEMP ( + owner_id VARCHAR2(256), + scope VARCHAR2(2048) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE client_redirect_uri_TEMP ( + owner_id VARCHAR2(256), + redirect_uri VARCHAR2(2048) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE client_grant_type_TEMP ( + owner_id VARCHAR2(256), + grant_type VARCHAR2(2000) +) ON COMMIT PRESERVE ROWS; + +CREATE GLOBAL TEMPORARY TABLE system_scope_TEMP ( + scope VARCHAR2(256), + description VARCHAR2(4000), + icon VARCHAR2(256), + restricted NUMBER(1), + default_scope NUMBER(1), + structured NUMBER(1), + structured_param_description VARCHAR2(256) +) ON COMMIT PRESERVE ROWS; diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql new file mode 100644 index 000000000..fc70a7ae4 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_index.sql @@ -0,0 +1,18 @@ +-- +-- Indexes for Oracle +-- + +CREATE INDEX at_tv_idx ON access_token(token_value); +CREATE INDEX ts_oi_idx ON token_scope(owner_id); +CREATE INDEX at_exp_idx ON access_token(expiration); +CREATE INDEX rf_ahi_idx ON refresh_token(auth_holder_id); +CREATE INDEX rf_tv_idx ON refresh_token(token_value); +CREATE INDEX at_ahi_idx ON access_token(auth_holder_id); +CREATE INDEX aha_oi_idx ON authentication_holder_authority(owner_id); +CREATE INDEX ahe_oi_idx ON authentication_holder_extension(owner_id); +CREATE INDEX ahrp_oi_idx ON authentication_holder_request_parameter(owner_id); +CREATE INDEX ahri_oi_idx ON authentication_holder_resource_id(owner_id); +CREATE INDEX ahrt_oi_idx ON authentication_holder_response_type(owner_id); +CREATE INDEX ahs_oi_idx ON authentication_holder_scope(owner_id); +CREATE INDEX ac_ahi_idx ON authorization_code(auth_holder_id); +CREATE INDEX suaa_oi_idx ON saved_user_auth_authority(owner_id); diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql new file mode 100644 index 000000000..9f430adac --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql @@ -0,0 +1,417 @@ +-- +-- Tables for OIDC Server functionality, Oracle +-- + +CREATE TABLE access_token ( + id NUMBER(19) NOT NULL PRIMARY KEY, + token_value VARCHAR2(4000), + expiration TIMESTAMP, + token_type VARCHAR2(256), + refresh_token_id NUMBER(19), + client_id NUMBER(19), + auth_holder_id NUMBER(19), + approved_site_id NUMBER(19) +); +CREATE SEQUENCE access_token_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE access_token_permissions ( + access_token_id NUMBER(19) NOT NULL, + permission_id NUMBER(19) NOT NULL +); + +CREATE TABLE address ( + id NUMBER(19) NOT NULL PRIMARY KEY, + formatted VARCHAR2(256), + street_address VARCHAR2(256), + locality VARCHAR2(256), + region VARCHAR2(256), + postal_code VARCHAR2(256), + country VARCHAR2(256) +); +CREATE SEQUENCE address_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE approved_site ( + id NUMBER(19) NOT NULL PRIMARY KEY, + user_id VARCHAR2(256), + client_id VARCHAR2(256), + creation_date TIMESTAMP, + access_date TIMESTAMP, + timeout_date TIMESTAMP, + whitelisted_site_id NUMBER(19) +); +CREATE SEQUENCE approved_site_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE approved_site_scope ( + owner_id NUMBER(19), + scope VARCHAR2(256) +); + +CREATE TABLE authentication_holder ( + id NUMBER(19) NOT NULL PRIMARY KEY, + user_auth_id NUMBER(19), + approved NUMBER(1), + redirect_uri VARCHAR2(2048), + client_id VARCHAR2(256), + + CONSTRAINT approved_check CHECK (approved in (1,0)) +); +CREATE SEQUENCE authentication_holder_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE auth_holder_authority ( + owner_id NUMBER(19), + authority VARCHAR2(256) +); + +CREATE TABLE auth_holder_resource_id ( + owner_id NUMBER(19), + resource_id VARCHAR2(2048) +); + +CREATE TABLE auth_holder_response_type ( + owner_id NUMBER(19), + response_type VARCHAR2(2048) +); + +CREATE TABLE auth_holder_extension ( + owner_id NUMBER(19), + extension VARCHAR2(2048), + val VARCHAR2(2048) +); + +CREATE TABLE authentication_holder_scope ( + owner_id NUMBER(19), + scope VARCHAR2(2048) +); + +CREATE TABLE auth_holder_request_parameter ( + owner_id NUMBER(19), + param VARCHAR2(2048), + val VARCHAR2(2048) +); + +CREATE TABLE saved_user_auth ( + id NUMBER(19) NOT NULL PRIMARY KEY, + name VARCHAR2(1024), + authenticated NUMBER(1), + source_class VARCHAR2(2048), + + CONSTRAINT authenticated_check CHECK (authenticated in (1,0)) +); +CREATE SEQUENCE saved_user_auth_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE saved_user_auth_authority ( + owner_id NUMBER(19), + authority VARCHAR2(256) +); + +CREATE TABLE client_authority ( + owner_id NUMBER(19), + authority VARCHAR2(256) +); + +CREATE TABLE authorization_code ( + id NUMBER(19) NOT NULL PRIMARY KEY, + code VARCHAR2(256), + auth_holder_id NUMBER(19), + expiration TIMESTAMP +); +CREATE SEQUENCE authorization_code_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE client_grant_type ( + owner_id NUMBER(19), + grant_type VARCHAR2(2000) +); + +CREATE TABLE client_response_type ( + owner_id NUMBER(19), + response_type VARCHAR2(2000) +); + +CREATE TABLE blacklisted_site ( + id NUMBER(19) NOT NULL PRIMARY KEY, + uri VARCHAR2(2048) +); +CREATE SEQUENCE blacklisted_site_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE client_details ( + id NUMBER(19) NOT NULL PRIMARY KEY, + + client_description VARCHAR2(1024), + reuse_refresh_tokens NUMBER(1) DEFAULT 1 NOT NULL, + dynamically_registered NUMBER(1) DEFAULT 0 NOT NULL, + allow_introspection NUMBER(1) DEFAULT 0 NOT NULL, + id_token_validity_seconds NUMBER(19) DEFAULT 600 NOT NULL, + + client_id VARCHAR2(256), + client_secret VARCHAR2(2048), + access_token_validity_seconds NUMBER(19), + refresh_token_validity_seconds NUMBER(19), + device_code_validity_seconds NUMBER(19), + + application_type VARCHAR2(256), + client_name VARCHAR2(256), + token_endpoint_auth_method VARCHAR2(256), + subject_type VARCHAR2(256), + + logo_uri VARCHAR2(2048), + policy_uri VARCHAR2(2048), + client_uri VARCHAR2(2048), + tos_uri VARCHAR2(2048), + + jwks_uri VARCHAR2(2048), + jwks CLOB, + sector_identifier_uri VARCHAR2(2048), + + request_object_signing_alg VARCHAR2(256), + + user_info_signed_response_alg VARCHAR2(256), + user_info_encrypted_resp_alg VARCHAR2(256), + user_info_encrypted_resp_enc VARCHAR2(256), + + id_token_signed_response_alg VARCHAR2(256), + id_token_encrypted_resp_alg VARCHAR2(256), + id_token_encrypted_resp_enc VARCHAR2(256), + + token_endpoint_auth_sign_alg VARCHAR2(256), + + default_max_age NUMBER(19), + require_auth_time NUMBER(1), + created_at TIMESTAMP, + initiate_login_uri VARCHAR2(2048), + clear_access_tokens_on_refresh NUMBER(1) DEFAULT 1 NOT NULL, + + software_statement VARCHAR(4096), + software_id VARCHAR(2048), + software_statement VARCHAR2(4000), + + code_challenge_method VARCHAR2(256), + + CONSTRAINT client_details_unique UNIQUE (client_id), + CONSTRAINT reuse_refresh_tokens_check CHECK (reuse_refresh_tokens in (1,0)), + CONSTRAINT dynamically_registered_check CHECK (dynamically_registered in (1,0)), + CONSTRAINT allow_introspection_check CHECK (allow_introspection in (1,0)), + CONSTRAINT require_auth_time_check CHECK (require_auth_time in (1,0)), + CONSTRAINT clear_acc_tok_on_refresh_check CHECK (clear_access_tokens_on_refresh in (1,0)) +); +CREATE SEQUENCE client_details_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE client_request_uri ( + owner_id NUMBER(19), + request_uri VARCHAR2(2000) +); + +CREATE TABLE client_post_logout_redir_uri ( + owner_id NUMBER(19), + post_logout_redirect_uri VARCHAR2(2000) +); + +CREATE TABLE client_default_acr_value ( + owner_id NUMBER(19), + default_acr_value VARCHAR2(2000) +); + +CREATE TABLE client_contact ( + owner_id NUMBER(19), + contact VARCHAR2(256) +); + +CREATE TABLE client_redirect_uri ( + owner_id NUMBER(19), + redirect_uri VARCHAR2(2048) +); + +CREATE TABLE client_claims_redirect_uri ( + owner_id NUMBER(19), + redirect_uri VARCHAR2(2048) +); + +CREATE TABLE refresh_token ( + id NUMBER(19) NOT NULL PRIMARY KEY, + token_value VARCHAR2(4000), + expiration TIMESTAMP, + auth_holder_id NUMBER(19), + client_id NUMBER(19) +); +CREATE SEQUENCE refresh_token_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE client_resource ( + owner_id NUMBER(19), + resource_id VARCHAR2(256) +); + +CREATE TABLE client_scope ( + owner_id NUMBER(19), + scope VARCHAR2(2048) +); + +CREATE TABLE token_scope ( + owner_id NUMBER(19), + scope VARCHAR2(2048) +); + +CREATE TABLE system_scope ( + id NUMBER(19) NOT NULL PRIMARY KEY, + scope VARCHAR2(256) NOT NULL, + description VARCHAR2(4000), + icon VARCHAR2(256), + restricted NUMBER(1) DEFAULT 0 NOT NULL, + default_scope NUMBER(1) DEFAULT 0 NOT NULL + + CONSTRAINT system_scope_unique UNIQUE (scope), + CONSTRAINT default_scope_check CHECK (default_scope in (1,0)), + CONSTRAINT restricted_check CHECK (restricted in (1,0)) +); +CREATE SEQUENCE system_scope_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE user_info ( + id NUMBER(19) NOT NULL PRIMARY KEY, + sub VARCHAR2(256), + preferred_username VARCHAR2(256), + name VARCHAR2(256), + given_name VARCHAR2(256), + family_name VARCHAR2(256), + middle_name VARCHAR2(256), + nickname VARCHAR2(256), + profile VARCHAR2(256), + picture VARCHAR2(256), + website VARCHAR2(256), + email VARCHAR2(256), + email_verified NUMBER(1), + gender VARCHAR2(256), + zone_info VARCHAR2(256), + locale VARCHAR2(256), + phone_number VARCHAR2(256), + phone_number_verified NUMBER(1), + address_id VARCHAR2(256), + updated_time VARCHAR2(256), + birthdate VARCHAR2(256), + src VARCHAR2(4000), + + CONSTRAINT email_verified_check CHECK (email_verified in (1,0)), + CONSTRAINT phone_number_verified_check CHECK (phone_number_verified in (1,0)) +); +CREATE SEQUENCE user_info_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE whitelisted_site ( + id NUMBER(19) NOT NULL PRIMARY KEY, + creator_user_id VARCHAR2(256), + client_id VARCHAR2(256) +); +CREATE SEQUENCE whitelisted_site_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE whitelisted_site_scope ( + owner_id NUMBER(19), + scope VARCHAR2(256) +); + +CREATE TABLE pairwise_identifier ( + id NUMBER(19) NOT NULL PRIMARY KEY, + identifier VARCHAR2(256), + sub VARCHAR2(256), + sector_identifier VARCHAR2(2048) +); +CREATE SEQUENCE pairwise_identifier_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE resource_set ( + id NUMBER(19) NOT NULL PRIMARY KEY, + name VARCHAR2(1024) NOT NULL, + uri VARCHAR2(1024), + icon_uri VARCHAR2(1024), + rs_type VARCHAR2(256), + owner VARCHAR2(256) NOT NULL, + client_id VARCHAR2(256) +); +CREATE SEQUENCE resource_set_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE resource_set_scope ( + owner_id NUMBER(19) NOT NULL, + scope VARCHAR2(256) NOT NULL +); + +CREATE TABLE permission_ticket ( + id NUMBER(19) NOT NULL PRIMARY KEY, + ticket VARCHAR2(256) NOT NULL, + permission_id NUMBER(19) NOT NULL, + expiration TIMESTAMP +); +CREATE SEQUENCE permission_ticket_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE permission ( + id NUMBER(19) NOT NULL PRIMARY KEY, + resource_set_id NUMBER(19) +); +CREATE SEQUENCE permission_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE permission_scope ( + owner_id NUMBER(19) NOT NULL, + scope VARCHAR2(256) NOT NULL +); + +CREATE TABLE claim ( + id NUMBER(19) NOT NULL PRIMARY KEY, + name VARCHAR2(256), + friendly_name VARCHAR2(1024), + claim_type VARCHAR2(1024), + claim_value VARCHAR2(1024) +); +CREATE SEQUENCE claim_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE claim_to_policy ( + policy_id NUMBER(19) NOT NULL, + claim_id NUMBER(19) NOT NULL +); + +CREATE TABLE claim_to_permission_ticket ( + permission_ticket_id NUMBER(19) NOT NULL, + claim_id NUMBER(19) NOT NULL +); + +CREATE TABLE policy ( + id NUMBER(19) NOT NULL PRIMARY KEY, + name VARCHAR2(1024), + resource_set_id NUMBER(19) +); +CREATE SEQUENCE policy_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE policy_scope ( + owner_id NUMBER(19) NOT NULL, + scope VARCHAR2(256) NOT NULL +); + +CREATE TABLE claim_token_format ( + owner_id NUMBER(19) NOT NULL, + claim_token_format VARCHAR2(1024) NOT NULL +); + +CREATE TABLE claim_issuer ( + owner_id NUMBER(19) NOT NULL, + issuer VARCHAR2(1024) NOT NULL +); + +CREATE TABLE saved_registered_client ( + id NUMBER(19) NOT NULL PRIMARY KEY, + issuer VARCHAR2(1024), + registered_client CLOB +); +CREATE SEQUENCE saved_registered_client_seq START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; + +CREATE TABLE IF NOT EXISTS device_code ( + id NUMBER(19) NOT NULL PRIMARY KEY, + device_code VARCHAR2(1024), + user_code VARCHAR2(1024), + expiration TIMESTAMP, + client_id VARCHAR2(256), + approved BOOLEAN, + auth_holder_id NUMBER(19) +); + +CREATE TABLE IF NOT EXISTS device_code_scope ( + owner_id NUMBER(19) NOT NULL, + scope VARCHAR2(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS device_code_request_parameter ( + owner_id NUMBER(19), + param VARCHAR2(2048), + val VARCHAR2(2048) +); diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql new file mode 100644 index 000000000..bb6bc82a2 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/scopes_oracle.sql @@ -0,0 +1,26 @@ +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', 0, 1); +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('profile', 'basic profile information', 'list-alt', 0, 1); +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('email', 'email address', 'envelope', 0, 1); +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('address', 'physical address', 'home', 0, 1); +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('phone', 'telephone number', 'bell', 0, 1, 0); +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('offline_access', 'offline access', 'time', 0, 0); +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +MERGE INTO system_scope + USING (SELECT scope, description, icon, restricted, default_scope FROM system_scope_TEMP) vals + ON (vals.scope = system_scope.scope) + WHEN NOT MATCHED THEN + INSERT (id, scope, description, icon, restricted, default_scope) VALUES(system_scope_seq.nextval, vals.scope, + vals.description, vals.icon, vals.restricted, vals.default_scope); diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql new file mode 100644 index 000000000..5b67ef668 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/security-schema_oracle.sql @@ -0,0 +1,18 @@ +-- +-- Tables for Spring Security's user details service +-- + +create table users( + username varchar2(50) not null primary key, + password varchar2(50) not null, + enabled number(1) not null, + + constraint enabled_check check (enabled in (1, 0)) +); + +create table authorities ( + username varchar2(50) not null, + authority varchar2(50) not null, + constraint fk_authorities_users foreign key(username) references users(username), + constraint ix_authority unique (username,authority) +); diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/users_oracle.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/users_oracle.sql new file mode 100644 index 000000000..732a13f16 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/users_oracle.sql @@ -0,0 +1,39 @@ +-- +-- Insert user information into the temporary tables. To add users to the Oracle database, edit things here. +-- + +INSERT INTO users_TEMP (username, password, enabled) VALUES ('admin','password',1); +INSERT INTO users_TEMP (username, password, enabled) VALUES ('user','password',1); + + +INSERT INTO authorities_TEMP (username, authority) VALUES ('admin','ROLE_ADMIN'); +INSERT INTO authorities_TEMP (username, authority) VALUES('admin','ROLE_USER'); +INSERT INTO authorities_TEMP (username, authority) VALUES('user','ROLE_USER'); + +-- By default, the username column here has to match the username column in the users table, above +INSERT INTO user_info_TEMP (sub, preferred_username, name, email, email_verified) VALUES ('90342.ASDFJWFA','admin','Demo Admin','admin@example.com', 1); +INSERT INTO user_info_TEMP (sub, preferred_username, name, email, email_verified) VALUES ('01921.FLANRJQW','user','Demo User','user@example.com', 1); + + +-- +-- Merge the temporary users safely into the database. This is a two-step process to keep users from being created on every startup with a persistent store. +-- + +MERGE INTO users + USING (SELECT username, password, enabled FROM users_TEMP) vals + ON (vals.username = users.username) + WHEN NOT MATCHED THEN + INSERT (username, password, enabled) VALUES(vals.username, vals.password, vals.enabled); + +MERGE INTO authorities + USING (SELECT username, authority FROM authorities_TEMP) vals + ON (vals.username = authorities.username AND vals.authority = authorities.authority) + WHEN NOT MATCHED THEN + INSERT (username,authority) values (vals.username, vals.authority); + +MERGE INTO user_info + USING (SELECT sub, preferred_username, name, email, email_verified FROM user_info_TEMP) vals + ON (vals.preferred_username = user_info.preferred_username) + WHEN NOT MATCHED THEN + INSERT (id, sub, preferred_username, name, email, email_verified) VALUES (user_info_seq.nextval, vals.sub, vals.preferred_username, vals.name, vals.email, + vals.email_verified); diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/clients.sql b/openid-connect-server-webapp/src/main/resources/db/psql/clients.sql new file mode 100644 index 000000000..bf14c2b2b --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/clients.sql @@ -0,0 +1,66 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +--SET AUTOCOMMIT = OFF; + +START TRANSACTION; + +-- +-- Insert client information into the temporary tables. To add clients to the HSQL database, edit things here. +-- + +INSERT INTO client_details_TEMP (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES + ('client', 'secret', 'Test Client', false, null, 3600, 600, true); + +INSERT INTO client_scope_TEMP (owner_id, scope) VALUES + ('client', 'openid'), + ('client', 'profile'), + ('client', 'email'), + ('client', 'address'), + ('client', 'phone'), + ('client', 'offline_access'); + +INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES + ('client', 'http://localhost/'), + ('client', 'http://localhost:8080/'); + +INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES + ('client', 'authorization_code'), + ('client', 'urn:ietf:params:oauth:grant_type:redelegate'), + ('client', 'implicit'), + ('client', 'refresh_token'); + +-- +-- Merge the temporary clients safely into the database. This is a two-step process to keep clients from being created on every startup with a persistent store. +-- + +INSERT INTO client_details (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) + SELECT client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection FROM client_details_TEMP + ON CONFLICT + DO NOTHING; + +INSERT INTO client_scope (scope) + SELECT scope FROM client_scope_TEMP, client_details WHERE client_details.client_id = client_scope_TEMP.owner_id + ON CONFLICT + DO NOTHING; + +INSERT INTO client_redirect_uri (redirect_uri) + SELECT redirect_uri FROM client_redirect_uri_TEMP, client_details WHERE client_details.client_id = client_redirect_uri_TEMP.owner_id + ON CONFLICT + DO NOTHING; + +INSERT INTO client_grant_type (grant_type) + SELECT grant_type FROM client_grant_type_TEMP, client_details WHERE client_details.client_id = client_grant_type_TEMP.owner_id + ON CONFLICT + DO NOTHING; + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +--SET AUTOCOMMIT = ON; + + diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_index.sql b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_index.sql new file mode 100644 index 000000000..a641ff821 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_index.sql @@ -0,0 +1,19 @@ +-- +-- Indexes for PostgreSQL +-- + +CREATE INDEX IF NOT EXISTS at_tv_idx ON access_token(token_value); +CREATE INDEX IF NOT EXISTS ts_oi_idx ON token_scope(owner_id); +CREATE INDEX IF NOT EXISTS at_exp_idx ON access_token(expiration); +CREATE INDEX IF NOT EXISTS rf_ahi_idx ON refresh_token(auth_holder_id); +CREATE INDEX IF NOT EXISTS rf_tv_idx ON refresh_token(token_value); +CREATE INDEX IF NOT EXISTS cd_ci_idx ON client_details(client_id); +CREATE INDEX IF NOT EXISTS at_ahi_idx ON access_token(auth_holder_id); +CREATE INDEX IF NOT EXISTS aha_oi_idx ON authentication_holder_authority(owner_id); +CREATE INDEX IF NOT EXISTS ahe_oi_idx ON authentication_holder_extension(owner_id); +CREATE INDEX IF NOT EXISTS ahrp_oi_idx ON authentication_holder_request_parameter(owner_id); +CREATE INDEX IF NOT EXISTS ahri_oi_idx ON authentication_holder_resource_id(owner_id); +CREATE INDEX IF NOT EXISTS ahrt_oi_idx ON authentication_holder_response_type(owner_id); +CREATE INDEX IF NOT EXISTS ahs_oi_idx ON authentication_holder_scope(owner_id); +CREATE INDEX IF NOT EXISTS ac_ahi_idx ON authorization_code(auth_holder_id); +CREATE INDEX IF NOT EXISTS suaa_oi_idx ON saved_user_auth_authority(owner_id); diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql new file mode 100644 index 000000000..be871b7e8 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql @@ -0,0 +1,384 @@ +-- +-- Tables for OIDC Server functionality, PostgreSQL +-- + +CREATE TABLE IF NOT EXISTS access_token ( + id BIGSERIAL PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + token_type VARCHAR(256), + refresh_token_id BIGINT, + client_id BIGINT, + auth_holder_id BIGINT, + approved_site_id BIGINT, + UNIQUE(token_value) +); + +CREATE TABLE IF NOT EXISTS access_token_permissions ( + access_token_id BIGINT NOT NULL, + permission_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS address ( + id BIGSERIAL PRIMARY KEY, + formatted VARCHAR(256), + street_address VARCHAR(256), + locality VARCHAR(256), + region VARCHAR(256), + postal_code VARCHAR(256), + country VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS approved_site ( + id BIGSERIAL PRIMARY KEY, + user_id VARCHAR(256), + client_id VARCHAR(256), + creation_date TIMESTAMP, + access_date TIMESTAMP, + timeout_date TIMESTAMP, + whitelisted_site_id BIGINT +); + +CREATE TABLE IF NOT EXISTS approved_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder ( + id BIGSERIAL PRIMARY KEY, + user_auth_id BIGINT, + approved BOOLEAN, + redirect_uri VARCHAR(2048), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_resource_id ( + owner_id BIGINT, + resource_id VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_response_type ( + owner_id BIGINT, + response_type VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_extension ( + owner_id BIGINT, + extension VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS authentication_holder_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(1024), + authenticated BOOLEAN, + source_class VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS saved_user_auth_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_authority ( + owner_id BIGINT, + authority VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS authorization_code ( + id BIGSERIAL PRIMARY KEY, + code VARCHAR(256), + auth_holder_id BIGINT, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS client_grant_type ( + owner_id BIGINT, + grant_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_response_type ( + owner_id BIGINT, + response_type VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS blacklisted_site ( + id BIGSERIAL PRIMARY KEY, + uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_details ( + id BIGSERIAL PRIMARY KEY, + + client_description VARCHAR(1024), + reuse_refresh_tokens BOOLEAN DEFAULT true NOT NULL, + dynamically_registered BOOLEAN DEFAULT false NOT NULL, + allow_introspection BOOLEAN DEFAULT false NOT NULL, + id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, + device_code_validity_seconds BIGINT, + + client_id VARCHAR(256), + client_secret VARCHAR(2048), + access_token_validity_seconds BIGINT, + refresh_token_validity_seconds BIGINT, + + application_type VARCHAR(256), + client_name VARCHAR(256), + token_endpoint_auth_method VARCHAR(256), + subject_type VARCHAR(256), + + logo_uri VARCHAR(2048), + policy_uri VARCHAR(2048), + client_uri VARCHAR(2048), + tos_uri VARCHAR(2048), + + jwks_uri VARCHAR(2048), + jwks VARCHAR(8192), + sector_identifier_uri VARCHAR(2048), + + request_object_signing_alg VARCHAR(256), + + user_info_signed_response_alg VARCHAR(256), + user_info_encrypted_response_alg VARCHAR(256), + user_info_encrypted_response_enc VARCHAR(256), + + id_token_signed_response_alg VARCHAR(256), + id_token_encrypted_response_alg VARCHAR(256), + id_token_encrypted_response_enc VARCHAR(256), + + token_endpoint_auth_signing_alg VARCHAR(256), + + default_max_age BIGINT, + require_auth_time BOOLEAN, + created_at TIMESTAMP, + initiate_login_uri VARCHAR(2048), + clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL, + + software_statement VARCHAR(4096), + software_id VARCHAR(2048), + software_version VARCHAR(2048), + + code_challenge_method VARCHAR(256), + + UNIQUE (client_id) +); + +CREATE TABLE IF NOT EXISTS client_request_uri ( + owner_id BIGINT, + request_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_post_logout_redirect_uri ( + owner_id BIGINT, + post_logout_redirect_uri VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_default_acr_value ( + owner_id BIGINT, + default_acr_value VARCHAR(2000) +); + +CREATE TABLE IF NOT EXISTS client_contact ( + owner_id BIGINT, + contact VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS client_claims_redirect_uri ( + owner_id BIGINT, + redirect_uri VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS refresh_token ( + id BIGSERIAL PRIMARY KEY, + token_value VARCHAR(4096), + expiration TIMESTAMP, + auth_holder_id BIGINT, + client_id BIGINT +); + +CREATE TABLE IF NOT EXISTS client_resource ( + owner_id BIGINT, + resource_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS client_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS token_scope ( + owner_id BIGINT, + scope VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS system_scope ( + id BIGSERIAL PRIMARY KEY, + scope VARCHAR(256) NOT NULL, + description VARCHAR(4096), + icon VARCHAR(256), + restricted BOOLEAN DEFAULT false NOT NULL, + default_scope BOOLEAN DEFAULT false NOT NULL, + UNIQUE (scope) +); + +CREATE TABLE IF NOT EXISTS user_info ( + id BIGSERIAL PRIMARY KEY, + sub VARCHAR(256), + preferred_username VARCHAR(256), + name VARCHAR(256), + given_name VARCHAR(256), + family_name VARCHAR(256), + middle_name VARCHAR(256), + nickname VARCHAR(256), + profile VARCHAR(256), + picture VARCHAR(256), + website VARCHAR(256), + email VARCHAR(256), + email_verified BOOLEAN, + gender VARCHAR(256), + zone_info VARCHAR(256), + locale VARCHAR(256), + phone_number VARCHAR(256), + phone_number_verified BOOLEAN, + address_id VARCHAR(256), + updated_time VARCHAR(256), + birthdate VARCHAR(256), + src VARCHAR(4096) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site ( + id BIGSERIAL PRIMARY KEY, + creator_user_id VARCHAR(256), + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS whitelisted_site_scope ( + owner_id BIGINT, + scope VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS pairwise_identifier ( + id BIGSERIAL PRIMARY KEY, + identifier VARCHAR(256), + sub VARCHAR(256), + sector_identifier VARCHAR(2048) +); + +CREATE TABLE IF NOT EXISTS resource_set ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(1024) NOT NULL, + uri VARCHAR(1024), + icon_uri VARCHAR(1024), + rs_type VARCHAR(256), + owner VARCHAR(256) NOT NULL, + client_id VARCHAR(256) +); + +CREATE TABLE IF NOT EXISTS resource_set_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS permission_ticket ( + id BIGSERIAL PRIMARY KEY, + ticket VARCHAR(256) NOT NULL, + permission_id BIGINT NOT NULL, + expiration TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS permission ( + id BIGSERIAL PRIMARY KEY, + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS permission_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(256), + friendly_name VARCHAR(1024), + claim_type VARCHAR(1024), + claim_value VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_to_policy ( + policy_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_to_permission_ticket ( + permission_ticket_id BIGINT NOT NULL, + claim_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS policy ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(1024), + resource_set_id BIGINT +); + +CREATE TABLE IF NOT EXISTS policy_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS claim_token_format ( + owner_id BIGINT NOT NULL, + claim_token_format VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS claim_issuer ( + owner_id BIGINT NOT NULL, + issuer VARCHAR(1024) +); + +CREATE TABLE IF NOT EXISTS saved_registered_client ( + id BIGSERIAL PRIMARY KEY, + issuer VARCHAR(1024), + registered_client VARCHAR(8192) +); + +CREATE TABLE IF NOT EXISTS device_code ( + id BIGSERIAL PRIMARY KEY, + device_code VARCHAR(1024), + user_code VARCHAR(1024), + expiration TIMESTAMP NULL, + client_id VARCHAR(256), + approved BOOLEAN, + auth_holder_id BIGINT +); + +CREATE TABLE IF NOT EXISTS device_code_scope ( + owner_id BIGINT NOT NULL, + scope VARCHAR(256) NOT NULL +); + +CREATE TABLE IF NOT EXISTS device_code_request_parameter ( + owner_id BIGINT, + param VARCHAR(2048), + val VARCHAR(2048) +); diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/scopes.sql b/openid-connect-server-webapp/src/main/resources/db/psql/scopes.sql new file mode 100644 index 000000000..140c72755 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/scopes.sql @@ -0,0 +1,33 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +--SET AUTOCOMMIT = OFF; + +START TRANSACTION; + +-- +-- Insert scope information into the temporary tables. +-- + +INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope) VALUES + ('openid', 'log in using your identity', 'user', false, true), + ('profile', 'basic profile information', 'list-alt', false, true), + ('email', 'email address', 'envelope', false, true), + ('address', 'physical address', 'home', false, true), + ('phone', 'telephone number', 'bell', false, true), + ('offline_access', 'offline access', 'time', false, false); + +-- +-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store. +-- + +INSERT INTO system_scope (scope, description, icon, restricted, default_scope) + SELECT scope, description, icon, restricted, default_scope FROM system_scope_TEMP + ON CONFLICT(scope) + DO NOTHING; + +COMMIT; + +--SET AUTOCOMMIT = ON; + diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/security-schema.sql b/openid-connect-server-webapp/src/main/resources/db/psql/security-schema.sql new file mode 100644 index 000000000..bc5d70b88 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/security-schema.sql @@ -0,0 +1,14 @@ +-- +-- Tables for Spring Security's user details service +-- + +create table IF NOT EXISTS users( + username varchar(50) not null primary key, + password varchar(50) not null, + enabled boolean not null); + + create table IF NOT EXISTS authorities ( + username varchar(50) not null, + authority varchar(50) not null, + constraint fk_authorities_users foreign key(username) references users(username), + constraint ix_authority unique (username,authority)); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/users.sql b/openid-connect-server-webapp/src/main/resources/db/psql/users.sql new file mode 100644 index 000000000..537330278 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/db/psql/users.sql @@ -0,0 +1,55 @@ +-- +-- Turn off autocommit and start a transaction so that we can use the temp tables +-- + +--SET AUTOCOMMIT FALSE; + +START TRANSACTION; + +-- +-- Insert user information into the temporary tables. To add users to the HSQL database, edit things here. +-- + +INSERT INTO users_TEMP (username, password, enabled) VALUES + ('admin','password',true), + ('user','password',true); + + +INSERT INTO authorities_TEMP (username, authority) VALUES + ('admin','ROLE_ADMIN'), + ('admin','ROLE_USER'), + ('user','ROLE_USER'); + +-- By default, the username column here has to match the username column in the users table, above +INSERT INTO user_info_TEMP (sub, preferred_username, name, email, email_verified) VALUES + ('90342.ASDFJWFA','admin','Demo Admin','admin@example.com', true), + ('01921.FLANRJQW','user','Demo User','user@example.com', true); + + +-- +-- Merge the temporary users safely into the database. This is a two-step process to keep users from being created on every startup with a persistent store. +-- + +INSERT INTO users + SELECT username, password, enabled FROM users_TEMP + ON CONFLICT(username) + DO NOTHING; + +INSERT INTO authorities + SELECT username, authority FROM authorities_TEMP + ON CONFLICT(username, authority) + DO NOTHING; + +INSERT INTO user_info (sub, preferred_username, name, email, email_verified) + SELECT sub, preferred_username, name, email, email_verified FROM user_info_TEMP + ON CONFLICT + DO NOTHING; + +-- +-- Close the transaction and turn autocommit back on +-- + +COMMIT; + +--SET AUTOCOMMIT TRUE; + diff --git a/openid-connect-server-webapp/src/main/resources/keystore.jwks b/openid-connect-server-webapp/src/main/resources/keystore.jwks new file mode 100644 index 000000000..461413ffe --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/keystore.jwks @@ -0,0 +1,12 @@ +{ + "keys": [ + { + "alg": "RS256", + "d": "PvBAngE3kkTnD3yDKo3wCvHJHm20kb9a0FVGLd0s2Y0E_3H2XnZC8-2zPhN6AQTjPhohSDCew20gzm76lyOvMqRiUP2Zpaopa1d2fGvNIQSdM07yKa6EivEYxqPQxa5esoZnexgnb9fom70I8n5OQRNQikwu-az26CsHX2zWMRodzSdN5CXHvb1PV09DmH8azTYwoMElPIqmcTfxiRw2Ov5ucmXXngKRFJgvfUgKd7v4ScBX7sQoQEjWEtt7ta0WvL3Ar5E1RAW4aHxuubZ6AtloxWCf17AAKw03dfP5RDm5TDmgm2B635ecJ7fTvneFmg8W_fdMTPRfBlCGNBp3wQ", + "e": "AQAB", + "n": "qt6yOiI_wCoCVlGO0MySsez0VkSqhPvDl3rfabOslx35mYEO-n4ABfIT5Gn2zN-CeIcOZ5ugAXvIIRWv5H55-tzjFazi5IKkOIMCiz5__MtsdxKCqGlZu2zt-BLpqTOAPiflNPpM3RUAlxKAhnYEqNha6-allPnFQupnW_eTYoyuzuedT7dSp90ry0ZcQDimntXWeaSbrYKCj9Rr9W1jn2uTowUuXaScKXTCjAmJVnsD75JNzQfa8DweklTyWQF-Y5Ky039I0VIu-0CIGhXY48GAFe2EFb8VpNhf07DP63p138RWQ1d3KPEM9mYJVpQC68j3wzDQYSljpLf9by7TGw", + "kty": "RSA", + "kid": "rsa1" + } + ] +} \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/resources/log4j.xml b/openid-connect-server-webapp/src/main/resources/log4j.xml new file mode 100644 index 000000000..caed28b32 --- /dev/null +++ b/openid-connect-server-webapp/src/main/resources/log4j.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/META-INF/MANIFEST.MF b/openid-connect-server-webapp/src/main/webapp/META-INF/MANIFEST.MF new file mode 100644 index 000000000..59499bce4 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml new file mode 100644 index 000000000..480b5780c --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /introspect + /revoke + /token + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml new file mode 100644 index 000000000..0ec4ce7f6 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml new file mode 100644 index 000000000..3b7a4faa8 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/authz-config.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml new file mode 100644 index 000000000..c1e47a8dc --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/crypto-config.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml new file mode 100644 index 000000000..67d8bd146 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/data-context.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml new file mode 100644 index 000000000..14fbcf2ea --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/endpoint-config.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml new file mode 100644 index 000000000..592d56a2e --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/jpa-config.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/local-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/local-config.xml new file mode 100644 index 000000000..3e5fef8e8 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/local-config.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml new file mode 100644 index 000000000..60cdb6b0f --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/locale-config.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml new file mode 100644 index 000000000..544f01c98 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/server-config.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml new file mode 100644 index 000000000..9306834d0 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/spring-servlet.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag new file mode 100644 index 000000000..d391a30ad --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/actionmenu.tag @@ -0,0 +1,20 @@ +<%@ tag language="java" pageEncoding="UTF-8"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="security" + uri="http://www.springframework.org/security/tags"%> + + +
  • +
  • +
  • +
  • +
  • +
    + +
  • +
  • +
  • +
  • + +
  • +
  • \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag new file mode 100644 index 000000000..4b0aa920a --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/copyright.tag @@ -0,0 +1,4 @@ +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +HEART Mode + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag new file mode 100644 index 000000000..2b95de6dc --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/footer.tag @@ -0,0 +1,45 @@ +<%@ attribute name="js" required="false"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +
    + + + + + + + + + + + + + + + + + + + + +
    + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/header.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/header.tag new file mode 100644 index 000000000..f4b4430cf --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/header.tag @@ -0,0 +1,86 @@ +<%@attribute name="title" required="false"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ tag import="com.google.gson.Gson" %> + + + + + + + + ${config.topbarTitle} - ${title} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag new file mode 100644 index 000000000..78bfe15cb --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/navmenu.tag @@ -0,0 +1,39 @@ +<%@attribute name="pageName"%> +<%@ tag language="java" pageEncoding="UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="security" + uri="http://www.springframework.org/security/tags"%> + + + +
  • + + +
  • +
    + + + +
  • +
    + +
  • +
    +
    + + +
  • +
    + +
  • +
    +
    + + +
  • +
    + +
  • +
    +
    diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag new file mode 100644 index 000000000..93f78c871 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/sidebar.tag @@ -0,0 +1,18 @@ +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> + + + +
    + +
    +
    + +
    + +
    +
    diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag new file mode 100644 index 000000000..1bce4a1c5 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/tags/topbar.tag @@ -0,0 +1,107 @@ +<%@attribute name="pageName" required="false"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml new file mode 100644 index 000000000..2b7513328 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/task-config.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml new file mode 100644 index 000000000..99951d230 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/ui-config.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + resources/js/client.js + resources/js/grant.js + resources/js/scope.js + resources/js/whitelist.js + resources/js/dynreg.js + resources/js/rsreg.js + resources/js/token.js + resources/js/blacklist.js + resources/js/profile.js + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml new file mode 100644 index 000000000..2aff94363 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/user-context.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/about.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/about.jsp new file mode 100644 index 000000000..1bf74f8b5 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/about.jsp @@ -0,0 +1,29 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + +
    +
    + +
    + +
    + +

    +

    + +

    + +
    + + +
    +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp new file mode 100644 index 000000000..4d3dda8ce --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approve.jsp @@ -0,0 +1,320 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ page import="org.springframework.security.core.AuthenticationException"%> +<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException"%> +<%@ page import="org.springframework.security.web.WebAttributes"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +
    + <% if (session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) != null && !(session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) instanceof UnapprovedClientAuthenticationException)) { %> +
    + × + +

    + (<%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %>) +

    +
    + <% } %> + + +
    +

      + + + + + + + + +

    + +
    + +
    +
    + + + + +
    +

    + + + + +

    +
    +
    + + +
    "> +

    + : +

    + +

    + +

    +

    + + + + + + + + + + + +

    +
    +
    +
    +
    + + +
      +
    • + +
    • +
    + + +
    + +
    + + +
    + +
    +
    +
      + +
    • : ">
    • +
      + +
    • : ">
    • +
      + +
    • : ">
    • +
      + +
    • :
    • +
      +
    +
    +
    +
    +
    +
    + + +
    +

    + : +

    + + +
    +
    + + + +
    +
    + + +
    + +
    +
    + +
    +
    +
    + : + + +
    +

    + : +

    +

    + +

    +
    +
    + + + + + +
    + " + > + + + + + + + + + + + +
    + : + + + +
    +
    + +
    + +
    +

    + + " + + + + + + + "? +

    + + + + + +   + +
    + + + +
    + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp new file mode 100644 index 000000000..c49e1e874 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/approveDevice.jsp @@ -0,0 +1,287 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ page import="org.springframework.security.core.AuthenticationException"%> +<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException"%> +<%@ page import="org.springframework.security.web.WebAttributes"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +
    + <% if (session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) != null && !(session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) instanceof UnapprovedClientAuthenticationException)) { %> +
    + × + +

    + (<%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %>) +

    +
    + <% } %> + + +
    +

      + + + + + + + + +

    + +
    + +
    +
    + + + + +
    +

    + + + + +

    +
    +
    + + +
    "> +

    + : +

    + +

    + +

    +

    + + + + + + + + + + + +

    +
    +
    +
    +
    + + +
      +
    • + +
    • +
    + + +
    + +
    + + +
    + +
    +
    +
      + +
    • : ">
    • +
      + +
    • : ">
    • +
      + +
    • : ">
    • +
      + +
    • :
    • +
      +
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    +
    + : + + +
    +

    + : +

    +

    + +

    +
    +
    + +
      + +
    • + + + + + + + + + + + + + + +
    • + : + +
    • +
      +
    +
    + " + > + + + + + + + + + +
    + +
    + +
    +

    + + " + + + + + + + "? +

    + + + + + + +   + +
    + + + +
    + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp new file mode 100644 index 000000000..cdfcdbcd1 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/contact.jsp @@ -0,0 +1,29 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + + +
    +
    + +
    +
    + +

    +

    + +

    + +
    + + +
    +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp new file mode 100644 index 000000000..80f601c63 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/deviceApproved.jsp @@ -0,0 +1,39 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ page import="org.springframework.security.core.AuthenticationException"%> +<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException"%> +<%@ page import="org.springframework.security.web.WebAttributes"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +
    + +
    +

    + + + + + + + +

    + + + +
    +
    + +
    +
    +
    + +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/error.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/error.jsp new file mode 100644 index 000000000..66c5f585e --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/error.jsp @@ -0,0 +1,48 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@page import="org.springframework.http.HttpStatus"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@page import="org.springframework.security.oauth2.common.exceptions.OAuth2Exception"%> +<% + +if (request.getAttribute("error") != null && request.getAttribute("error") instanceof OAuth2Exception) { + request.setAttribute("errorCode", ((OAuth2Exception)request.getAttribute("error")).getOAuth2ErrorCode()); + request.setAttribute("message", ((OAuth2Exception)request.getAttribute("error")).getMessage()); +} else if (request.getAttribute("javax.servlet.error.exception") != null) { + Throwable t = (Throwable)request.getAttribute("javax.servlet.error.exception"); + request.setAttribute("errorCode", t.getClass().getSimpleName() + " (" + request.getAttribute("javax.servlet.error.status_code") + ")"); + request.setAttribute("message", t.getMessage()); +} else if (request.getAttribute("javax.servlet.error.status_code") != null) { + Integer code = (Integer)request.getAttribute("javax.servlet.error.status_code"); + HttpStatus status = HttpStatus.valueOf(code); + request.setAttribute("errorCode", status.toString() + " " + status.getReasonPhrase()); + request.setAttribute("message", request.getAttribute("javax.servlet.error.message")); +} else { + request.setAttribute("errorCode", "Server error"); + request.setAttribute("message", "See the logs for details"); +} + +%> + + + +
    +
    +
    +
    +

    + +

    +

    + +

    +

    + +
    + +
    +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/home.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/home.jsp new file mode 100644 index 000000000..5fa2495a5 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/home.jsp @@ -0,0 +1,84 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    +

    +
    +
    +
    + +
    +
    +

    + +

    + +

    »

    +
    +
    +

    +

    + +

    +
    + +
    +
    + +
    +
    +

    + +

    + +

    + + + +

    +
    +
    + +
    +
    +
    + + + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/login.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/login.jsp new file mode 100644 index 000000000..5be8f9b2a --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/login.jsp @@ -0,0 +1,51 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + +
    + +

    + + +
    +
    + + +
    +
    +
    +
    +
    + + " autocorrect="off" autocapitalize="off" autocomplete="off" spellcheck="false" value="" id="j_username" name="username"> +
    +
    +
    +
    + + " autocorrect="off" autocapitalize="off" autocomplete="off" spellcheck="false" id="j_password" name="password"> +
    +
    +
    + + " name="submit"> +
    +
    +
    +
    +
    + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp new file mode 100644 index 000000000..a53199e2f --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/logoutConfirmation.jsp @@ -0,0 +1,55 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ page import="org.springframework.security.core.AuthenticationException"%> +<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException"%> +<%@ page import="org.springframework.security.web.WebAttributes"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +
    + +
    + +

    + +
    + +
    +
    + + +
    + + +   + + + + + + + + + +
    +
    + +
    + + +   + +
    +
    + +
    + +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp new file mode 100644 index 000000000..548819d59 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/manage.jsp @@ -0,0 +1,47 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + + + + +
    +
    + +
    +
    + +
    +
    +

    :

    +

    +
    +
    +
    +
    +

    ...

    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp new file mode 100644 index 000000000..03f93974b --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/postLogout.jsp @@ -0,0 +1,26 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> + + + + +
    + +
    +

    + + +
    +
    + +
    +
    +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp new file mode 100644 index 000000000..9551acbff --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/requestUserCode.jsp @@ -0,0 +1,61 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ page import="org.springframework.security.core.AuthenticationException"%> +<%@ page import="org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException"%> +<%@ page import="org.springframework.security.web.WebAttributes"%> +<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +
    + +
    + +

    + + + + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + +
    +
    + + +
    +
    + +
    + +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/stats.jsp b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/stats.jsp new file mode 100644 index 000000000..8e97e6b36 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/views/stats.jsp @@ -0,0 +1,28 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%> +<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + + +
    +
    + +
    +
    +

    + +

    + + + +

    +
    +
    +
    +
    + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/web.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..618db1df4 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,79 @@ + + + + + + + + + contextConfigLocation + + /WEB-INF/application-context.xml + + + + + + org.springframework.web.context.ContextLoaderListener + + + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + contextAttribute + org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring + + + + + springSecurityFilterChain + /* + + + + + spring + org.springframework.web.servlet.DispatcherServlet + 1 + + + + spring + / + + + + + *.jsp + true + + + + + /error + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.properties b/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.properties new file mode 100644 index 000000000..2bc4d6e62 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright 2018 The MIT Internet Trust Consortium +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### +preProcessors=cssImport +postProcessors=lessCss diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.xml new file mode 100644 index 000000000..471fd1843 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/wro.xml @@ -0,0 +1,23 @@ + + + + /less/bootstrap.less + + + /less/bootstrap-responsive.less + + \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/less/accordion.less b/openid-connect-server-webapp/src/main/webapp/less/accordion.less new file mode 100644 index 000000000..d63523bc8 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/accordion.less @@ -0,0 +1,34 @@ +// +// Accordion +// -------------------------------------------------- + + +// Parent container +.accordion { + margin-bottom: @baseLineHeight; +} + +// Group == heading + body +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + .border-radius(@baseBorderRadius); +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +// General toggle styles +.accordion-toggle { + cursor: pointer; +} + +// Inner needs the styles because you can't animate properly with any styles on the element +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/alerts.less b/openid-connect-server-webapp/src/main/webapp/less/alerts.less new file mode 100644 index 000000000..0116b191b --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/alerts.less @@ -0,0 +1,79 @@ +// +// Alerts +// -------------------------------------------------- + + +// Base styles +// ------------------------- + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: @baseLineHeight; + text-shadow: 0 1px 0 rgba(255,255,255,.5); + background-color: @warningBackground; + border: 1px solid @warningBorder; + .border-radius(@baseBorderRadius); +} +.alert, +.alert h4 { + // Specified for the h4 to prevent conflicts of changing @headingsColor + color: @warningText; +} +.alert h4 { + margin: 0; +} + +// Adjust close link position +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: @baseLineHeight; +} + + +// Alternate styles +// ------------------------- + +.alert-success { + background-color: @successBackground; + border-color: @successBorder; + color: @successText; +} +.alert-success h4 { + color: @successText; +} +.alert-danger, +.alert-error { + background-color: @errorBackground; + border-color: @errorBorder; + color: @errorText; +} +.alert-danger h4, +.alert-error h4 { + color: @errorText; +} +.alert-info { + background-color: @infoBackground; + border-color: @infoBorder; + color: @infoText; +} +.alert-info h4 { + color: @infoText; +} + + +// Block alerts +// ------------------------- + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/bootstrap-responsive.less b/openid-connect-server-webapp/src/main/webapp/less/bootstrap-responsive.less new file mode 100644 index 000000000..3d4c58cab --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/bootstrap-responsive.less @@ -0,0 +1,48 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + + +// Responsive.less +// For phone and tablet devices +// ------------------------------------------------------------- + + +// REPEAT VARIABLES & MIXINS +// ------------------------- +// Required since we compile the responsive stuff separately + +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + + +// RESPONSIVE CLASSES +// ------------------ + +@import "responsive-utilities.less"; + + +// MEDIA QUERIES +// ------------------ + +// Large desktops +@import "responsive-1200px-min.less"; + +// Tablets to regular desktops +@import "responsive-768px-979px.less"; + +// Phones to portrait tablets and narrow desktops +@import "responsive-767px-max.less"; + + +// RESPONSIVE NAVBAR +// ------------------ + +// From 979px and below, show a button to toggle navbar contents +@import "responsive-navbar.less"; diff --git a/openid-connect-server-webapp/src/main/webapp/less/bootstrap.less b/openid-connect-server-webapp/src/main/webapp/less/bootstrap.less new file mode 100644 index 000000000..3eabae144 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/bootstrap.less @@ -0,0 +1,63 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +// Core variables and mixins +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + +// CSS Reset +@import "reset.less"; + +// Grid system and page structure +@import "scaffolding.less"; +@import "grid.less"; +@import "layouts.less"; + +// Base CSS +@import "type.less"; +@import "code.less"; +@import "forms.less"; +@import "tables.less"; + +// Components: common +@import "sprites.less"; +@import "dropdowns.less"; +@import "wells.less"; +@import "component-animations.less"; +@import "close.less"; + +// Components: Buttons & Alerts +@import "buttons.less"; +@import "button-groups.less"; +@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less + +// Components: Nav +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; + +// Components: Popovers +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; + +// Components: Misc +@import "thumbnails.less"; +@import "media.less"; +@import "labels-badges.less"; +@import "progress-bars.less"; +@import "accordion.less"; +@import "carousel.less"; +@import "hero-unit.less"; + +// Utility classes +@import "utilities.less"; // Has to be last to override when necessary diff --git a/openid-connect-server-webapp/src/main/webapp/less/breadcrumbs.less b/openid-connect-server-webapp/src/main/webapp/less/breadcrumbs.less new file mode 100644 index 000000000..f753df6be --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/breadcrumbs.less @@ -0,0 +1,24 @@ +// +// Breadcrumbs +// -------------------------------------------------- + + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 @baseLineHeight; + list-style: none; + background-color: #f5f5f5; + .border-radius(@baseBorderRadius); + > li { + display: inline-block; + .ie7-inline-block(); + text-shadow: 0 1px 0 @white; + > .divider { + padding: 0 5px; + color: #ccc; + } + } + > .active { + color: @grayLight; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/button-groups.less b/openid-connect-server-webapp/src/main/webapp/less/button-groups.less new file mode 100644 index 000000000..55cdc6033 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/button-groups.less @@ -0,0 +1,229 @@ +// +// Button groups +// -------------------------------------------------- + + +// Make the div behave like a button +.btn-group { + position: relative; + display: inline-block; + .ie7-inline-block(); + font-size: 0; // remove as part 1 of font-size inline-block hack + vertical-align: middle; // match .btn alignment given font-size hack above + white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page) + .ie7-restore-left-whitespace(); +} + +// Space out series of button groups +.btn-group + .btn-group { + margin-left: 5px; +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + font-size: 0; // Hack to remove whitespace that results from using inline-block + margin-top: @baseLineHeight / 2; + margin-bottom: @baseLineHeight / 2; + > .btn + .btn, + > .btn-group + .btn, + > .btn + .btn-group { + margin-left: 5px; + } +} + +// Float them, remove border radius, then re-add to first and last elements +.btn-group > .btn { + position: relative; + .border-radius(0); +} +.btn-group > .btn + .btn { + margin-left: -1px; +} +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack +} + +// Reset fonts for other sizes +.btn-group > .btn-mini { + font-size: @fontSizeMini; +} +.btn-group > .btn-small { + font-size: @fontSizeSmall; +} +.btn-group > .btn-large { + font-size: @fontSizeLarge; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + .border-top-left-radius(@baseBorderRadius); + .border-bottom-left-radius(@baseBorderRadius); +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + .border-top-right-radius(@baseBorderRadius); + .border-bottom-right-radius(@baseBorderRadius); +} +// Reset corners for large buttons +.btn-group > .btn.large:first-child { + margin-left: 0; + .border-top-left-radius(@borderRadiusLarge); + .border-bottom-left-radius(@borderRadiusLarge); +} +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + .border-top-right-radius(@borderRadiusLarge); + .border-bottom-right-radius(@borderRadiusLarge); +} + +// On hover/focus/active, bring the proper btn to front +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group > .btn-mini + .dropdown-toggle { + padding-left: 5px; + padding-right: 5px; + *padding-top: 2px; + *padding-bottom: 2px; +} +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} +.btn-group > .btn-large + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; + *padding-top: 7px; + *padding-bottom: 7px; +} + +.btn-group.open { + + // The clickable button for toggling the menu + // Remove the gradient and set the same inset shadow as the :active state + .dropdown-toggle { + background-image: none; + .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); + } + + // Keep the hover's background when dropdown is open + .btn.dropdown-toggle { + background-color: @btnBackgroundHighlight; + } + .btn-primary.dropdown-toggle { + background-color: @btnPrimaryBackgroundHighlight; + } + .btn-warning.dropdown-toggle { + background-color: @btnWarningBackgroundHighlight; + } + .btn-danger.dropdown-toggle { + background-color: @btnDangerBackgroundHighlight; + } + .btn-success.dropdown-toggle { + background-color: @btnSuccessBackgroundHighlight; + } + .btn-info.dropdown-toggle { + background-color: @btnInfoBackgroundHighlight; + } + .btn-inverse.dropdown-toggle { + background-color: @btnInverseBackgroundHighlight; + } +} + + +// Reposition the caret +.btn .caret { + margin-top: 8px; + margin-left: 0; +} +// Carets in other button sizes +.btn-large .caret { + margin-top: 6px; +} +.btn-large .caret { + border-left-width: 5px; + border-right-width: 5px; + border-top-width: 5px; +} +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} +// Upside down carets for .dropup +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + + + +// Account for other colors +.btn-primary, +.btn-warning, +.btn-danger, +.btn-info, +.btn-success, +.btn-inverse { + .caret { + border-top-color: @white; + border-bottom-color: @white; + } +} + + + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + display: inline-block; // makes buttons only take up the width they need + .ie7-inline-block(); +} +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + .border-radius(0); +} +.btn-group-vertical > .btn + .btn { + margin-left: 0; + margin-top: -1px; +} +.btn-group-vertical > .btn:first-child { + .border-radius(@baseBorderRadius @baseBorderRadius 0 0); +} +.btn-group-vertical > .btn:last-child { + .border-radius(0 0 @baseBorderRadius @baseBorderRadius); +} +.btn-group-vertical > .btn-large:first-child { + .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0); +} +.btn-group-vertical > .btn-large:last-child { + .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge); +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/buttons.less b/openid-connect-server-webapp/src/main/webapp/less/buttons.less new file mode 100644 index 000000000..4cd4d862b --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/buttons.less @@ -0,0 +1,228 @@ +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +// Core +.btn { + display: inline-block; + .ie7-inline-block(); + padding: 4px 12px; + margin-bottom: 0; // For input.btn + font-size: @baseFontSize; + line-height: @baseLineHeight; + text-align: center; + vertical-align: middle; + cursor: pointer; + .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75)); + border: 1px solid @btnBorder; + *border: 0; // Remove the border to prevent IE7's black border on input:focus + border-bottom-color: darken(@btnBorder, 10%); + .border-radius(@baseBorderRadius); + .ie7-restore-left-whitespace(); // Give IE7 some love + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); + + // Hover/focus state + &:hover, + &:focus { + color: @grayDark; + text-decoration: none; + background-position: 0 -15px; + + // transition is only when going to hover/focus, otherwise the background + // behind the gradient (there for IE<=9 fallback) gets mismatched + .transition(background-position .1s linear); + } + + // Focus state for keyboard and accessibility + &:focus { + .tab-focus(); + } + + // Active state + &.active, + &:active { + background-image: none; + outline: 0; + .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); + } + + // Disabled state + &.disabled, + &[disabled] { + cursor: default; + background-image: none; + .opacity(65); + .box-shadow(none); + } + +} + + + +// Button Sizes +// -------------------------------------------------- + +// Large +.btn-large { + padding: @paddingLarge; + font-size: @fontSizeLarge; + .border-radius(@borderRadiusLarge); +} +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +// Small +.btn-small { + padding: @paddingSmall; + font-size: @fontSizeSmall; + .border-radius(@borderRadiusSmall); +} +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +// Mini +.btn-mini { + padding: @paddingMini; + font-size: @fontSizeMini; + .border-radius(@borderRadiusSmall); +} + + +// Block button +// ------------------------- + +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; + .box-sizing(border-box); +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} + + + +// Alternate buttons +// -------------------------------------------------- + +// Provide *some* extra contrast for those who can get it +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255,255,255,.75); +} + +// Set the backgrounds +// ------------------------- +.btn-primary { + .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight); +} +// Warning appears are orange +.btn-warning { + .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight); +} +// Danger and error appear as red +.btn-danger { + .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight); +} +// Success appears as green +.btn-success { + .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight); +} +// Info appears as a neutral blue +.btn-info { + .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight); +} +// Inverse appears as dark gray +.btn-inverse { + .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight); +} + + +// Cross-browser Jank +// -------------------------------------------------- + +button.btn, +input[type="submit"].btn { + + // Firefox 3.6 only I believe + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + // IE7 has some default padding on button controls + *padding-top: 3px; + *padding-bottom: 3px; + + &.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; + } + &.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; + } + &.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; + } +} + + +// Link buttons +// -------------------------------------------------- + +// Make a button look and behave like a link +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + .box-shadow(none); +} +.btn-link { + border-color: transparent; + cursor: pointer; + color: @linkColor; + .border-radius(0); +} +.btn-link:hover, +.btn-link:focus { + color: @linkColorHover; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: @grayDark; + text-decoration: none; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/carousel.less b/openid-connect-server-webapp/src/main/webapp/less/carousel.less new file mode 100644 index 000000000..55bc05014 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/carousel.less @@ -0,0 +1,158 @@ +// +// Carousel +// -------------------------------------------------- + + +.carousel { + position: relative; + margin-bottom: @baseLineHeight; + line-height: 1; +} + +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} + +.carousel-inner { + + > .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + + // Account for jankitude on images + > img, + > a > img { + display: block; + line-height: 1; + } + } + + > .active, + > .next, + > .prev { display: block; } + + > .active { + left: 0; + } + + > .next, + > .prev { + position: absolute; + top: 0; + width: 100%; + } + + > .next { + left: 100%; + } + > .prev { + left: -100%; + } + > .next.left, + > .prev.right { + left: 0; + } + + > .active.left { + left: -100%; + } + > .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: @white; + text-align: center; + background: @grayDarker; + border: 3px solid @white; + .border-radius(23px); + .opacity(50); + + // we can't have this transition here + // because webkit cancels the carousel + // animation if you trip this while + // in the middle of another animation + // ;_; + // .transition(opacity .2s linear); + + // Reposition the right one + &.right { + left: auto; + right: 15px; + } + + // Hover/focus state + &:hover, + &:focus { + color: @white; + text-decoration: none; + .opacity(90); + } +} + +// Carousel indicator pips +// ----------------------------- +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; + + li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255,255,255,.25); + border-radius: 5px; + } + .active { + background-color: #fff; + } +} + +// Caption for text below images +// ----------------------------- + +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 15px; + background: @grayDark; + background: rgba(0,0,0,.75); +} +.carousel-caption h4, +.carousel-caption p { + color: @white; + line-height: @baseLineHeight; +} +.carousel-caption h4 { + margin: 0 0 5px; +} +.carousel-caption p { + margin-bottom: 0; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/close.less b/openid-connect-server-webapp/src/main/webapp/less/close.less new file mode 100644 index 000000000..4c626bda6 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/close.less @@ -0,0 +1,32 @@ +// +// Close icons +// -------------------------------------------------- + + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: @baseLineHeight; + color: @black; + text-shadow: 0 1px 0 rgba(255,255,255,1); + .opacity(20); + &:hover, + &:focus { + color: @black; + text-decoration: none; + cursor: pointer; + .opacity(40); + } +} + +// Additional properties for button version +// iOS requires the button element instead of an anchor tag. +// If you want the anchor version, it requires `href="#"`. +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/less/code.less b/openid-connect-server-webapp/src/main/webapp/less/code.less new file mode 100644 index 000000000..266a926e7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/code.less @@ -0,0 +1,61 @@ +// +// Code (inline and blocK) +// -------------------------------------------------- + + +// Inline and block code styles +code, +pre { + padding: 0 3px 2px; + #font > #family > .monospace; + font-size: @baseFontSize - 2; + color: @grayDark; + .border-radius(3px); +} + +// Inline code +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + white-space: nowrap; +} + +// Blocks of code +pre { + display: block; + padding: (@baseLineHeight - 1) / 2; + margin: 0 0 @baseLineHeight / 2; + font-size: @baseFontSize - 1; // 14px to 13px + line-height: @baseLineHeight; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; // fallback for IE7-8 + border: 1px solid rgba(0,0,0,.15); + .border-radius(@baseBorderRadius); + + // Make prettyprint styles more spaced out for readability + &.prettyprint { + margin-bottom: @baseLineHeight; + } + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/less/component-animations.less b/openid-connect-server-webapp/src/main/webapp/less/component-animations.less new file mode 100644 index 000000000..d614263a7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/component-animations.less @@ -0,0 +1,22 @@ +// +// Component animations +// -------------------------------------------------- + + +.fade { + opacity: 0; + .transition(opacity .15s linear); + &.in { + opacity: 1; + } +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + .transition(height .35s ease); + &.in { + height: auto; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/dropdowns.less b/openid-connect-server-webapp/src/main/webapp/less/dropdowns.less new file mode 100644 index 000000000..9e47b4715 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/dropdowns.less @@ -0,0 +1,248 @@ +// +// Dropdown menus +// -------------------------------------------------- + + +// Use the .menu class on any
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle { + // The caret makes the toggle a bit too tall in IE7 + *margin-bottom: -3px; +} +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +// Dropdown arrow/caret +// -------------------- +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid @black; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +// Place the caret +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +// The dropdown menu (ul) +// ---------------------- +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindexDropdown; + display: none; // none by default, but block on "open" of the menu + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; // override default ul + list-style: none; + background-color: @dropdownBackground; + border: 1px solid #ccc; // Fallback for IE7-8 + border: 1px solid @dropdownBorder; + *border-right-width: 2px; + *border-bottom-width: 2px; + .border-radius(6px); + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + + // Aligns the dropdown menu to right + &.pull-right { + right: 0; + left: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdownDividerTop, @dropdownDividerBottom); + } + + // Links within the dropdown menu + > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: @baseLineHeight; + color: @dropdownLinkColor; + white-space: nowrap; + } +} + +// Hover/Focus state +// ----------- +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + text-decoration: none; + color: @dropdownLinkColorHover; + #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%)); +} + +// Active state +// ------------ +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: @dropdownLinkColorActive; + text-decoration: none; + outline: 0; + #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%)); +} + +// Disabled state +// -------------- +// Gray out text and ensure the hover/focus state remains gray +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: @grayLight; +} +// Nuke hover/focus effects +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + .reset-filter(); + cursor: default; +} + +// Open state for the dropdown +// --------------------------- +.open { + // IE7's z-index only goes to the nearest positioned ancestor, which would + // make the menu appear below buttons that appeared later on the page + *z-index: @zindexDropdown; + + & > .dropdown-menu { + display: block; + } +} + +// Backdrop to catch body clicks on mobile, etc. +// --------------------------- +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: @zindexDropdown - 10; +} + +// Right aligned dropdowns +// --------------------------- +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// ------------------------------------------------------ +// Just add .dropup after the standard .dropdown class and you're set, bro. +// TODO: abstract this so that the navbar fixed styles are not placed here? +.dropup, +.navbar-fixed-bottom .dropdown { + // Reverse the caret + .caret { + border-top: 0; + border-bottom: 4px solid @black; + content: ""; + } + // Different positioning for bottom up menu + .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; + } +} + +// Sub menus +// --------------------------- +.dropdown-submenu { + position: relative; +} +// Default dropdowns +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + .border-radius(0 6px 6px 6px); +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +// Dropups +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + .border-radius(5px 5px 5px 0); +} + +// Caret to indicate there is a submenu +.dropdown-submenu > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: darken(@dropdownBackground, 20%); + margin-top: 5px; + margin-right: -10px; +} +.dropdown-submenu:hover > a:after { + border-left-color: @dropdownLinkColorHover; +} + +// Left aligned submenus +.dropdown-submenu.pull-left { + // Undo the float + // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere. + float: none; + + // Positioning the submenu + > .dropdown-menu { + left: -100%; + margin-left: 10px; + .border-radius(6px 0 6px 6px); + } +} + +// Tweak nav headers +// ----------------- +// Increase padding from 15px to 20px on sides +.dropdown .dropdown-menu .nav-header { + padding-left: 20px; + padding-right: 20px; +} + +// Typeahead +// --------- +.typeahead { + z-index: 1051; + margin-top: 2px; // give it some space to breathe + .border-radius(@baseBorderRadius); +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/forms.less b/openid-connect-server-webapp/src/main/webapp/less/forms.less new file mode 100644 index 000000000..06767bdd3 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/forms.less @@ -0,0 +1,690 @@ +// +// Forms +// -------------------------------------------------- + + +// GENERAL STYLES +// -------------- + +// Make all forms have space below them +form { + margin: 0 0 @baseLineHeight; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +// Groups of fields with labels on top (legends) +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @baseLineHeight; + font-size: @baseFontSize * 1.5; + line-height: @baseLineHeight * 2; + color: @grayDark; + border: 0; + border-bottom: 1px solid #e5e5e5; + + // Small + small { + font-size: @baseLineHeight * .75; + color: @grayLight; + } +} + +// Set font for forms +label, +input, +button, +select, +textarea { + #font > .shorthand(@baseFontSize,normal,@baseLineHeight); // Set size, weight, line-height here +} +input, +button, +select, +textarea { + font-family: @baseFontFamily; // And only set font-family here for those that need it (note the missing label element) +} + +// Identify controls by their labels +label { + display: block; + margin-bottom: 5px; +} + +// Form controls +// ------------------------- + +// Shared size and type resets +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: @baseLineHeight; + padding: 4px 6px; + margin-bottom: @baseLineHeight / 2; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @gray; + .border-radius(@inputBorderRadius); + vertical-align: middle; +} + +// Reset appearance properties for textual inputs and textarea +// Declare width for legacy (can't be on input[type=*] selectors or it's too specific) +input, +textarea, +.uneditable-input { + width: 206px; // plus 12px padding and 2px border +} +// Reset height since textareas have rows +textarea { + height: auto; +} +// Everything else +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: @inputBackground; + border: 1px solid @inputBorder; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + .transition(~"border linear .2s, box-shadow linear .2s"); + + // Focus state + &:focus { + border-color: rgba(82,168,236,.8); + outline: 0; + outline: thin dotted \9; /* IE6-9 */ + .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)"); + } +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + *margin-top: 0; /* IE7 */ + margin-top: 1px \9; /* IE8-9 */ + line-height: normal; +} + +// Reset width of input images, buttons, radios, checkboxes +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; // Override of generic input selector +} + +// Set the height of select and file controls to match text inputs +select, +input[type="file"] { + height: @inputHeight; /* In IE7, the height of the select element cannot be changed by height, only font-size */ + *margin-top: 4px; /* For IE7, add top margin to align select with labels */ + line-height: @inputHeight; +} + +// Make select elements obey height by applying a border +select { + width: 220px; // default input width + 10px of padding that doesn't get applied + border: 1px solid @inputBorder; + background-color: @inputBackground; // Chrome on Linux and Mobile Safari need background-color +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Focus for select, file, radio, and checkbox +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + + +// Uneditable inputs +// ------------------------- + +// Make uneditable inputs look inactive +.uneditable-input, +.uneditable-textarea { + color: @grayLight; + background-color: darken(@inputBackground, 1%); + border-color: @inputBorder; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.025)); + cursor: not-allowed; +} + +// For text that needs to appear as an input but should not be an input +.uneditable-input { + overflow: hidden; // prevent text from wrapping, but still cut it off like an input does + white-space: nowrap; +} + +// Make uneditable textareas behave like a textarea +.uneditable-textarea { + width: auto; + height: auto; +} + + +// Placeholder +// ------------------------- + +// Placeholder text gets special styles because when browsers invalidate entire lines if it doesn't understand a selector +input, +textarea { + .placeholder(); +} + + +// CHECKBOXES & RADIOS +// ------------------- + +// Indent the labels to position radios/checkboxes as hanging +.radio, +.checkbox { + min-height: @baseLineHeight; // clear the floating input if there is no label text + padding-left: 20px; +} +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +// Move the options list down to align with labels +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; // has to be padding because margin collaspes +} + +// Radios and checkboxes on same line +// TODO v3: Convert .inline to .control-inline +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; // space out consecutive inline controls +} + + + +// INPUT SIZES +// ----------- + +// General classes for quick sizes +.input-mini { width: 60px; } +.input-small { width: 90px; } +.input-medium { width: 150px; } +.input-large { width: 210px; } +.input-xlarge { width: 270px; } +.input-xxlarge { width: 530px; } + +// Grid style input sizes +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +// Redeclare since the fluid row class is more specific +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} +// Ensure input-prepend/append never wraps +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + + + +// GRID SIZING FOR INPUTS +// ---------------------- + +// Grid sizes +#grid > .input(@gridColumnWidth, @gridGutterWidth); + +// Control row for multiple inputs per line +.controls-row { + .clearfix(); // Clear the float from controls +} + +// Float to collapse white-space for proper grid alignment +.controls-row [class*="span"], +// Redeclare the fluid grid collapse since we undo the float for inputs +.row-fluid .controls-row [class*="span"] { + float: left; +} +// Explicity set top padding on all checkboxes/radios, not just first-child +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + + + + +// DISABLED STATE +// -------------- + +// Disabled and read-only inputs +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: @inputDisabledBackground; +} +// Explicitly reset the colors here +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + + + + +// FORM FIELD FEEDBACK STATES +// -------------------------- + +// Warning +.control-group.warning { + .formFieldState(@warningText, @warningText, @warningBackground); +} +// Error +.control-group.error { + .formFieldState(@errorText, @errorText, @errorBackground); +} +// Success +.control-group.success { + .formFieldState(@successText, @successText, @successBackground); +} +// Success +.control-group.info { + .formFieldState(@infoText, @infoText, @infoBackground); +} + +// HTML5 invalid states +// Shares styles with the .control-group.error above +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; + &:focus { + border-color: darken(#ee5f5b, 10%); + @shadow: 0 0 6px lighten(#ee5f5b, 20%); + .box-shadow(@shadow); + } +} + + + +// FORM ACTIONS +// ------------ + +.form-actions { + padding: (@baseLineHeight - 1) 20px @baseLineHeight; + margin-top: @baseLineHeight; + margin-bottom: @baseLineHeight; + background-color: @formActionsBackground; + border-top: 1px solid #e5e5e5; + .clearfix(); // Adding clearfix to allow for .pull-right button containers +} + + + +// HELP TEXT +// --------- + +.help-block, +.help-inline { + color: lighten(@textColor, 15%); // lighten the text some for contrast +} + +.help-block { + display: block; // account for any element using help-block + margin-bottom: @baseLineHeight / 2; +} + +.help-inline { + display: inline-block; + .ie7-inline-block(); + vertical-align: middle; + padding-left: 5px; +} + + + +// INPUT GROUPS +// ------------ + +// Allow us to put symbols and text within the input field for a cleaner look +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: @baseLineHeight / 2; + vertical-align: middle; + font-size: 0; // white space collapse hack + white-space: nowrap; // Prevent span and input from separating + + // Reset the white space collapse hack + input, + select, + .uneditable-input, + .dropdown-menu, + .popover { + font-size: @baseFontSize; + } + + input, + select, + .uneditable-input { + position: relative; // placed here by default so that on :focus we can place the input above the .add-on for full border and box-shadow goodness + margin-bottom: 0; // prevent bottom margin from screwing up alignment in stacked forms + *margin-left: 0; + vertical-align: top; + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + // Make input on top when focused so blue border and shadow always show + &:focus { + z-index: 2; + } + } + .add-on { + display: inline-block; + width: auto; + height: @baseLineHeight; + min-width: 16px; + padding: 4px 5px; + font-size: @baseFontSize; + font-weight: normal; + line-height: @baseLineHeight; + text-align: center; + text-shadow: 0 1px 0 @white; + background-color: @grayLighter; + border: 1px solid #ccc; + } + .add-on, + .btn, + .btn-group > .dropdown-toggle { + vertical-align: top; + .border-radius(0); + } + .active { + background-color: lighten(@green, 30); + border-color: @green; + } +} + +.input-prepend { + .add-on, + .btn { + margin-right: -1px; + } + .add-on:first-child, + .btn:first-child { + // FYI, `.btn:first-child` accounts for a button group that's prepended + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + } +} + +.input-append { + input, + select, + .uneditable-input { + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + + .btn-group .btn:last-child { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + } + .add-on, + .btn, + .btn-group { + margin-left: -1px; + } + .add-on:last-child, + .btn:last-child, + .btn-group:last-child > .dropdown-toggle { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } +} + +// Remove all border-radius for inputs with both prepend and append +.input-prepend.input-append { + input, + select, + .uneditable-input { + .border-radius(0); + + .btn-group .btn { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + } + .add-on:first-child, + .btn:first-child { + margin-right: -1px; + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + } + .add-on:last-child, + .btn:last-child { + margin-left: -1px; + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + .btn-group:first-child { + margin-left: 0; + } +} + + + + +// SEARCH FORM +// ----------- + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */ + margin-bottom: 0; // Remove the default margin on all inputs + .border-radius(15px); +} + +/* Allow for input prepend/append in search forms */ +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + .border-radius(0); // Override due to specificity +} +.form-search .input-append .search-query { + .border-radius(14px 0 0 14px); +} +.form-search .input-append .btn { + .border-radius(0 14px 14px 0); +} +.form-search .input-prepend .search-query { + .border-radius(0 14px 14px 0); +} +.form-search .input-prepend .btn { + .border-radius(14px 0 0 14px); +} + + + + +// HORIZONTAL & VERTICAL FORMS +// --------------------------- + +// Common properties +// ----------------- + +.form-search, +.form-inline, +.form-horizontal { + input, + textarea, + select, + .help-inline, + .uneditable-input, + .input-prepend, + .input-append { + display: inline-block; + .ie7-inline-block(); + margin-bottom: 0; + vertical-align: middle; + } + // Re-hide hidden elements due to specifity + .hide { + display: none; + } +} +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} +// Remove margin for input-prepend/-append +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} +// Inline checkbox/radio labels (remove padding on left) +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} +// Remove float and margin, set to inline-block +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + + +// Margin to space out fieldsets +.control-group { + margin-bottom: @baseLineHeight / 2; +} + +// Legend collapses margin, so next element is responsible for spacing +legend + .control-group { + margin-top: @baseLineHeight; + -webkit-margin-top-collapse: separate; +} + +// Horizontal-specific styles +// -------------------------- + +.form-horizontal { + // Increase spacing between groups + .control-group { + margin-bottom: @baseLineHeight; + .clearfix(); + } + // Float the labels left + .control-label { + float: left; + width: @horizontalComponentOffset - 20; + padding-top: 5px; + text-align: right; + } + // Move over all input controls and content + .controls { + // Super jank IE7 fix to ensure the inputs in .input-append and input-prepend + // don't inherit the margin of the parent, in this case .controls + *display: inline-block; + *padding-left: 20px; + margin-left: @horizontalComponentOffset; + *margin-left: 0; + &:first-child { + *padding-left: @horizontalComponentOffset; + } + } + // Remove bottom margin on block level help text since that's accounted for on .control-group + .help-block { + margin-bottom: 0; + } + // And apply it only to .help-block instances that follow a form control + input, + select, + textarea, + .uneditable-input, + .input-prepend, + .input-append { + + .help-block { + margin-top: @baseLineHeight / 2; + } + } + // Move over buttons in .form-actions to align with .controls + .form-actions { + padding-left: @horizontalComponentOffset; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/grid.less b/openid-connect-server-webapp/src/main/webapp/less/grid.less new file mode 100644 index 000000000..750d20351 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/grid.less @@ -0,0 +1,21 @@ +// +// Grid system +// -------------------------------------------------- + + +// Fixed (940px) +#grid > .core(@gridColumnWidth, @gridGutterWidth); + +// Fluid (940px) +#grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); + +// Reset utility classes due to specificity +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/hero-unit.less b/openid-connect-server-webapp/src/main/webapp/less/hero-unit.less new file mode 100644 index 000000000..763d86aee --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/hero-unit.less @@ -0,0 +1,25 @@ +// +// Hero unit +// -------------------------------------------------- + + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: @baseLineHeight * 1.5; + color: @heroUnitLeadColor; + background-color: @heroUnitBackground; + .border-radius(6px); + h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + color: @heroUnitHeadingColor; + letter-spacing: -1px; + } + li { + line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/labels-badges.less b/openid-connect-server-webapp/src/main/webapp/less/labels-badges.less new file mode 100644 index 000000000..bc321fe5c --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/labels-badges.less @@ -0,0 +1,84 @@ +// +// Labels and badges +// -------------------------------------------------- + + +// Base classes +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: @baseFontSize * .846; + font-weight: bold; + line-height: 14px; // ensure proper line-height if floated + color: @white; + vertical-align: baseline; + white-space: nowrap; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + background-color: @grayLight; +} +// Set unique padding and border-radii +.label { + .border-radius(3px); +} +.badge { + padding-left: 9px; + padding-right: 9px; + .border-radius(9px); +} + +// Empty labels/badges collapse +.label, +.badge { + &:empty { + display: none; + } +} + +// Hover/focus state, but only for links +a { + &.label:hover, + &.label:focus, + &.badge:hover, + &.badge:focus { + color: @white; + text-decoration: none; + cursor: pointer; + } +} + +// Colors +// Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute) +.label, +.badge { + // Important (red) + &-important { background-color: @errorText; } + &-important[href] { background-color: darken(@errorText, 10%); } + // Warnings (orange) + &-warning { background-color: @orange; } + &-warning[href] { background-color: darken(@orange, 10%); } + // Success (green) + &-success { background-color: @successText; } + &-success[href] { background-color: darken(@successText, 10%); } + // Info (turquoise) + &-info { background-color: @infoText; } + &-info[href] { background-color: darken(@infoText, 10%); } + // Inverse (black) + &-inverse { background-color: @grayDark; } + &-inverse[href] { background-color: darken(@grayDark, 10%); } +} + +// Quick fix for labels/badges in buttons +.btn { + .label, + .badge { + position: relative; + top: -1px; + } +} +.btn-mini { + .label, + .badge { + top: 0; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/layouts.less b/openid-connect-server-webapp/src/main/webapp/less/layouts.less new file mode 100644 index 000000000..24a206211 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/layouts.less @@ -0,0 +1,16 @@ +// +// Layouts +// -------------------------------------------------- + + +// Container (centered, fixed-width layouts) +.container { + .container-fixed(); +} + +// Fluid layouts (left aligned, with sidebar, min- & max-width content) +.container-fluid { + padding-right: @gridGutterWidth; + padding-left: @gridGutterWidth; + .clearfix(); +} \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/less/media.less b/openid-connect-server-webapp/src/main/webapp/less/media.less new file mode 100644 index 000000000..e461e446d --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/media.less @@ -0,0 +1,55 @@ +// Media objects +// Source: http://stubbornella.org/content/?p=497 +// -------------------------------------------------- + + +// Common styles +// ------------------------- + +// Clear the floats +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +// Proper spacing between instances of .media +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} + +// For images and videos, set to block +.media-object { + display: block; +} + +// Reset margins on headings for tighter default spacing +.media-heading { + margin: 0 0 5px; +} + + +// Media image alignment +// ------------------------- + +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} + + +// Media list variation +// ------------------------- + +// Undo default ul/ol styles +.media-list { + margin-left: 0; + list-style: none; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/mixins.less b/openid-connect-server-webapp/src/main/webapp/less/mixins.less new file mode 100644 index 000000000..857561e9a --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/mixins.less @@ -0,0 +1,702 @@ +// +// Mixins +// -------------------------------------------------- + + +// UTILITY MIXINS +// -------------------------------------------------- + +// Clearfix +// -------- +// For clearing floats like a boss h5bp.com/q +.clearfix { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + // Fixes Opera/contenteditable bug: + // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 + line-height: 0; + } + &:after { + clear: both; + } +} + +// Webkit-style focus +// ------------------ +.tab-focus() { + // Default + outline: thin dotted #333; + // Webkit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +// Center-align a block level element +// ---------------------------------- +.center-block() { + display: block; + margin-left: auto; + margin-right: auto; +} + +// IE7 inline-block +// ---------------- +.ie7-inline-block() { + *display: inline; /* IE7 inline-block hack */ + *zoom: 1; +} + +// IE7 likes to collapse whitespace on either side of the inline-block elements. +// Ems because we're attempting to match the width of a space character. Left +// version is for form buttons, which typically come after other elements, and +// right version is for icons, which come before. Applying both is ok, but it will +// mean that space between those elements will be .6em (~2 space characters) in IE7, +// instead of the 1 space in other browsers. +.ie7-restore-left-whitespace() { + *margin-left: .3em; + + &:first-child { + *margin-left: 0; + } +} + +.ie7-restore-right-whitespace() { + *margin-right: .3em; +} + +// Sizing shortcuts +// ------------------------- +.size(@height, @width) { + width: @width; + height: @height; +} +.square(@size) { + .size(@size, @size); +} + +// Placeholder text +// ------------------------- +.placeholder(@color: @placeholderText) { + &:-moz-placeholder { + color: @color; + } + &:-ms-input-placeholder { + color: @color; + } + &::-webkit-input-placeholder { + color: @color; + } +} + +// Text overflow +// ------------------------- +// Requires inline-block or block for proper styling +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +// CSS image replacement +// ------------------------- +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + + +// FONTS +// -------------------------------------------------- + +#font { + #family { + .serif() { + font-family: @serifFontFamily; + } + .sans-serif() { + font-family: @sansFontFamily; + } + .monospace() { + font-family: @monoFontFamily; + } + } + .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + font-size: @size; + font-weight: @weight; + line-height: @lineHeight; + } + .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .sans-serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .monospace; + #font > .shorthand(@size, @weight, @lineHeight); + } +} + + +// FORMS +// -------------------------------------------------- + +// Block level inputs +.input-block-level { + display: block; + width: 100%; + min-height: @inputHeight; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + .box-sizing(border-box); // Makes inputs behave like true block-level elements +} + + + +// Mixin for form field states +.formFieldState(@textColor: #555, @borderColor: #ccc, @backgroundColor: #f5f5f5) { + // Set the text color + .control-label, + .help-block, + .help-inline { + color: @textColor; + } + // Style inputs accordingly + .checkbox, + .radio, + input, + select, + textarea { + color: @textColor; + } + input, + select, + textarea { + border-color: @borderColor; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work + &:focus { + border-color: darken(@borderColor, 10%); + @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@borderColor, 20%); + .box-shadow(@shadow); + } + } + // Give a small background color for input-prepend/-append + .input-prepend .add-on, + .input-append .add-on { + color: @textColor; + background-color: @backgroundColor; + border-color: @textColor; + } +} + + + +// CSS3 PROPERTIES +// -------------------------------------------------- + +// Border Radius +.border-radius(@radius) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +// Single Corner Border Radius +.border-top-left-radius(@radius) { + -webkit-border-top-left-radius: @radius; + -moz-border-radius-topleft: @radius; + border-top-left-radius: @radius; +} +.border-top-right-radius(@radius) { + -webkit-border-top-right-radius: @radius; + -moz-border-radius-topright: @radius; + border-top-right-radius: @radius; +} +.border-bottom-right-radius(@radius) { + -webkit-border-bottom-right-radius: @radius; + -moz-border-radius-bottomright: @radius; + border-bottom-right-radius: @radius; +} +.border-bottom-left-radius(@radius) { + -webkit-border-bottom-left-radius: @radius; + -moz-border-radius-bottomleft: @radius; + border-bottom-left-radius: @radius; +} + +// Single Side Border Radius +.border-top-radius(@radius) { + .border-top-right-radius(@radius); + .border-top-left-radius(@radius); +} +.border-right-radius(@radius) { + .border-top-right-radius(@radius); + .border-bottom-right-radius(@radius); +} +.border-bottom-radius(@radius) { + .border-bottom-right-radius(@radius); + .border-bottom-left-radius(@radius); +} +.border-left-radius(@radius) { + .border-top-left-radius(@radius); + .border-bottom-left-radius(@radius); +} + +// Drop shadows +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; + -moz-box-shadow: @shadow; + box-shadow: @shadow; +} + +// Transitions +.transition(@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + -moz-transition-delay: @transition-delay; + -o-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} +.transition-duration(@transition-duration) { + -webkit-transition-duration: @transition-duration; + -moz-transition-duration: @transition-duration; + -o-transition-duration: @transition-duration; + transition-duration: @transition-duration; +} + +// Transformations +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -moz-transform: scale(@ratio); + -ms-transform: scale(@ratio); + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.translate(@x, @y) { + -webkit-transform: translate(@x, @y); + -moz-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.skew(@x, @y) { + -webkit-transform: skew(@x, @y); + -moz-transform: skew(@x, @y); + -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885 + -o-transform: skew(@x, @y); + transform: skew(@x, @y); + -webkit-backface-visibility: hidden; // See https://github.com/twbs/bootstrap/issues/5319 +} +.translate3d(@x, @y, @z) { + -webkit-transform: translate3d(@x, @y, @z); + -moz-transform: translate3d(@x, @y, @z); + -o-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} + +// Backface visibility +// Prevent browsers from flickering when using CSS 3D transforms. +// Default value is `visible`, but can be changed to `hidden +// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples +.backface-visibility(@visibility){ + -webkit-backface-visibility: @visibility; + -moz-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Background clipping +// Heads up: FF 3.6 and under need "padding" instead of "padding-box" +.background-clip(@clip) { + -webkit-background-clip: @clip; + -moz-background-clip: @clip; + background-clip: @clip; +} + +// Background sizing +.background-size(@size) { + -webkit-background-size: @size; + -moz-background-size: @size; + -o-background-size: @size; + background-size: @size; +} + + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// User select +// For selecting text on the page +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; + -o-user-select: @select; + user-select: @select; +} + +// Resize anything +.resizable(@direction) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Safari fix +} + +// CSS3 Content Columns +.content-columns(@columnCount, @columnGap: @gridGutterWidth) { + -webkit-column-count: @columnCount; + -moz-column-count: @columnCount; + column-count: @columnCount; + -webkit-column-gap: @columnGap; + -moz-column-gap: @columnGap; + column-gap: @columnGap; +} + +// Optional hyphenation +.hyphens(@mode: auto) { + word-wrap: break-word; + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + -ms-hyphens: @mode; + -o-hyphens: @mode; + hyphens: @mode; +} + +// Opacity +.opacity(@opacity) { + opacity: @opacity / 100; + filter: ~"alpha(opacity=@{opacity})"; +} + + + +// BACKGROUNDS +// -------------------------------------------------- + +// Add an alphatransparency value to any background or border color (via Elyse Holladay) +#translucent { + .background(@color: @white, @alpha: 1) { + background-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + } + .border(@color: @white, @alpha: 1) { + border-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + .background-clip(padding-box); + } +} + +// Gradient Bar Colors for buttons and alerts +.gradientBar(@primaryColor, @secondaryColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + color: @textColor; + text-shadow: @textShadow; + #gradient > .vertical(@primaryColor, @secondaryColor); + border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); + border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%); +} + +// Gradients +#gradient { + .horizontal(@startColor: #555, @endColor: #333) { + background-color: @endColor; + background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .directional(@startColor: #555, @endColor: #333, @deg: 45deg) { + background-color: @endColor; + background-repeat: repeat-x; + background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10 + } + .horizontal-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(left, linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(to right, @startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + + .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@innerColor: #555, @outerColor: #333) { + background-color: @outerColor; + background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor)); + background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor); + background-image: -moz-radial-gradient(circle, @innerColor, @outerColor); + background-image: -o-radial-gradient(circle, @innerColor, @outerColor); + background-repeat: no-repeat; + } + .striped(@color: #555, @angle: 45deg) { + background-color: @color; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + } +} +// Reset filters for IE +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} + + + +// COMPONENT MIXINS +// -------------------------------------------------- + +// Horizontal dividers +// ------------------------- +// Dividers (basically an hr) within dropdowns and nav lists +.nav-divider(@top: #e5e5e5, @bottom: @white) { + // IE7 needs a set width since we gave a height. Restricting just + // to IE7 to keep the 1px left/right space in other browsers. + // It is unclear where IE is getting the extra space that we need + // to negative-margin away, but so it goes. + *width: 100%; + height: 1px; + margin: ((@baseLineHeight / 2) - 1) 1px; // 8px 1px + *margin: -5px 0 5px; + overflow: hidden; + background-color: @top; + border-bottom: 1px solid @bottom; +} + +// Button backgrounds +// ------------------ +.buttonBackground(@startColor, @endColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + // gradientBar will set the background to a pleasing blend of these, to support IE<=9 + .gradientBar(@startColor, @endColor, @textColor, @textShadow); + *background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + .reset-filter(); + + // in these cases the gradient won't cover the background, so we override + &:hover, &:focus, &:active, &.active, &.disabled, &[disabled] { + color: @textColor; + background-color: @endColor; + *background-color: darken(@endColor, 5%); + } + + // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves + &:active, + &.active { + background-color: darken(@endColor, 10%) e("\9"); + } +} + +// Navbar vertical align +// ------------------------- +// Vertically center elements in the navbar. +// Example: an element has a height of 30px, so write out `.navbarVerticalAlign(30px);` to calculate the appropriate top margin. +.navbarVerticalAlign(@elementHeight) { + margin-top: (@navbarHeight - @elementHeight) / 2; +} + + + +// Grid System +// ----------- + +// Centered container element +.container-fixed() { + margin-right: auto; + margin-left: auto; + .clearfix(); +} + +// Table columns +.tableColumns(@columnSpan: 1) { + float: none; // undo default grid column styles + width: ((@gridColumnWidth) * @columnSpan) + (@gridGutterWidth * (@columnSpan - 1)) - 16; // 16 is total padding on left and right of table cells + margin-left: 0; // undo default grid column styles +} + +// Make a Grid +// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior +.makeRow() { + margin-left: @gridGutterWidth * -1; + .clearfix(); +} +.makeColumn(@columns: 1, @offset: 0) { + float: left; + margin-left: (@gridColumnWidth * @offset) + (@gridGutterWidth * (@offset - 1)) + (@gridGutterWidth * 2); + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); +} + +// The Grid +#grid { + + .core (@gridColumnWidth, @gridGutterWidth) { + + .spanX (@index) when (@index > 0) { + .span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + .offset@{index} { .offset(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1)); + } + + .span (@columns) { + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); + } + + .row { + margin-left: @gridGutterWidth * -1; + .clearfix(); + } + + [class*="span"] { + float: left; + min-height: 1px; // prevent collapsing columns + margin-left: @gridGutterWidth; + } + + // Set the container width, and override it for fixed navbars in media queries + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { .span(@gridColumns); } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + + } + + .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) { + + .spanX (@index) when (@index > 0) { + .span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + .offset@{index} { .offset(@index); } + .offset@{index}:first-child { .offsetFirstChild(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%); + } + + .offsetFirstChild (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + + .span (@columns) { + width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)); + *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%); + } + + .row-fluid { + width: 100%; + .clearfix(); + [class*="span"] { + .input-block-level(); + float: left; + margin-left: @fluidGridGutterWidth; + *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + [class*="span"]:first-child { + margin-left: 0; + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @fluidGridGutterWidth; + } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + } + + } + + .input(@gridColumnWidth, @gridGutterWidth) { + + .spanX (@index) when (@index > 0) { + input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .span(@columns) { + width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 14; + } + + input, + textarea, + .uneditable-input { + margin-left: 0; // override margin-left from core grid system + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @gridGutterWidth; + } + + // generate .spanX + .spanX (@gridColumns); + + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/modals.less b/openid-connect-server-webapp/src/main/webapp/less/modals.less new file mode 100644 index 000000000..8e272d409 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/modals.less @@ -0,0 +1,95 @@ +// +// Modals +// -------------------------------------------------- + +// Background +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindexModalBackdrop; + background-color: @black; + // Fade for backdrop + &.fade { opacity: 0; } +} + +.modal-backdrop, +.modal-backdrop.fade.in { + .opacity(80); +} + +// Base modal +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: @zindexModal; + width: 560px; + margin-left: -280px; + background-color: @white; + border: 1px solid #999; + border: 1px solid rgba(0,0,0,.3); + *border: 1px solid #999; /* IE6-7 */ + .border-radius(6px); + .box-shadow(0 3px 7px rgba(0,0,0,0.3)); + .background-clip(padding-box); + // Remove focus outline from opened modal + outline: none; + + &.fade { + .transition(e('opacity .3s linear, top .3s ease-out')); + top: -25%; + } + &.fade.in { top: 10%; } +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; + // Close icon + .close { margin-top: 2px; } + // Heading + h3 { + margin: 0; + line-height: 30px; + } +} + +// Body (where all modal content resides) +.modal-body { + position: relative; + overflow-y: auto; + max-height: 400px; + padding: 15px; +} +// Remove bottom margin if need be +.modal-form { + margin-bottom: 0; +} + +// Footer (for actions) +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; // right align buttons + background-color: #f5f5f5; + border-top: 1px solid #ddd; + .border-radius(0 0 6px 6px); + .box-shadow(inset 0 1px 0 @white); + .clearfix(); // clear it in case folks use .pull-* classes on buttons + + // Properly space out buttons + .btn + .btn { + margin-left: 5px; + margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs + } + // but override that for button groups + .btn-group .btn + .btn { + margin-left: -1px; + } + // and override it for block buttons as well + .btn-block + .btn-block { + margin-left: 0; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/navbar.less b/openid-connect-server-webapp/src/main/webapp/less/navbar.less new file mode 100644 index 000000000..93d09bcad --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/navbar.less @@ -0,0 +1,497 @@ +// +// Navbars (Redux) +// -------------------------------------------------- + + +// COMMON STYLES +// ------------- + +// Base class and wrapper +.navbar { + overflow: visible; + margin-bottom: @baseLineHeight; + + // Fix for IE7's bad z-indexing so dropdowns don't appear below content that follows the navbar + *position: relative; + *z-index: 2; +} + +// Inner for background effects +// Gradient is applied to its own element because overflow visible is not honored by IE when filter is present +.navbar-inner { + min-height: @navbarHeight; + padding-left: 20px; + padding-right: 20px; + #gradient > .vertical(@navbarBackgroundHighlight, @navbarBackground); + border: 1px solid @navbarBorder; + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 4px rgba(0,0,0,.065)); + + // Prevent floats from breaking the navbar + .clearfix(); +} + +// Set width to auto for default container +// We then reset it for fixed navbars in the #gridSystem mixin +.navbar .container { + width: auto; +} + +// Override the default collapsed state +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + + +// Brand: website or project name +// ------------------------- +.navbar .brand { + float: left; + display: block; + // Vertically center the text given @navbarHeight + padding: ((@navbarHeight - @baseLineHeight) / 2) 20px ((@navbarHeight - @baseLineHeight) / 2); + margin-left: -20px; // negative indent to left-align the text down the page + font-size: 20px; + font-weight: 200; + color: @navbarBrandColor; + text-shadow: 0 1px 0 @navbarBackgroundHighlight; + &:hover, + &:focus { + text-decoration: none; + } +} + +// Plain text in topbar +// ------------------------- +.navbar-text { + margin-bottom: 0; + line-height: @navbarHeight; + color: @navbarText; +} + +// Janky solution for now to account for links outside the .nav +// ------------------------- +.navbar-link { + color: @navbarLinkColor; + &:hover, + &:focus { + color: @navbarLinkColorHover; + } +} + +// Dividers in navbar +// ------------------------- +.navbar .divider-vertical { + height: @navbarHeight; + margin: 0 9px; + border-left: 1px solid @navbarBackground; + border-right: 1px solid @navbarBackgroundHighlight; +} + +// Buttons in navbar +// ------------------------- +.navbar .btn, +.navbar .btn-group { + .navbarVerticalAlign(30px); // Vertically center in navbar +} +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; // then undo the margin here so we don't accidentally double it +} + +// Navbar forms +// ------------------------- +.navbar-form { + margin-bottom: 0; // remove default bottom margin + .clearfix(); + input, + select, + .radio, + .checkbox { + .navbarVerticalAlign(30px); // Vertically center in navbar + } + input, + select, + .btn { + display: inline-block; + margin-bottom: 0; + } + input[type="image"], + input[type="checkbox"], + input[type="radio"] { + margin-top: 3px; + } + .input-append, + .input-prepend { + margin-top: 5px; + white-space: nowrap; // preven two items from separating within a .navbar-form that has .pull-left + input { + margin-top: 0; // remove the margin on top since it's on the parent + } + } +} + +// Navbar search +// ------------------------- +.navbar-search { + position: relative; + float: left; + .navbarVerticalAlign(30px); // Vertically center in navbar + margin-bottom: 0; + .search-query { + margin-bottom: 0; + padding: 4px 14px; + #font > .sans-serif(13px, normal, 1); + .border-radius(15px); // redeclare because of specificity of the type attribute + } +} + + + +// Static navbar +// ------------------------- + +.navbar-static-top { + position: static; + margin-bottom: 0; // remove 18px margin for default navbar + .navbar-inner { + .border-radius(0); + } +} + + + +// Fixed navbar +// ------------------------- + +// Shared (top/bottom) styles +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: @zindexFixedNavbar; + margin-bottom: 0; // remove 18px margin for default navbar +} +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-left: 0; + padding-right: 0; + .border-radius(0); +} + +// Reset container width +// Required here as we reset the width earlier on and the grid mixins don't override early enough +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + #grid > .core > .span(@gridColumns); +} + +// Fixed to top +.navbar-fixed-top { + top: 0; +} +.navbar-fixed-top, +.navbar-static-top { + .navbar-inner { + .box-shadow(~"0 1px 10px rgba(0,0,0,.1)"); + } +} + +// Fixed to bottom +.navbar-fixed-bottom { + bottom: 0; + .navbar-inner { + .box-shadow(~"0 -1px 10px rgba(0,0,0,.1)"); + } +} + + + +// NAVIGATION +// ---------- + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; // redeclare due to specificity + margin-right: 0; // remove margin on float right nav +} +.navbar .nav > li { + float: left; +} + +// Links +.navbar .nav > li > a { + float: none; + // Vertically center the text given @navbarHeight + padding: ((@navbarHeight - @baseLineHeight) / 2) 15px ((@navbarHeight - @baseLineHeight) / 2); + color: @navbarLinkColor; + text-decoration: none; + text-shadow: 0 1px 0 @navbarBackgroundHighlight; +} +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +// Hover/focus +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + background-color: @navbarLinkBackgroundHover; // "transparent" is default to differentiate :hover/:focus from .active + color: @navbarLinkColorHover; + text-decoration: none; +} + +// Active nav items +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: @navbarLinkColorActive; + text-decoration: none; + background-color: @navbarLinkBackgroundActive; + .box-shadow(inset 0 3px 8px rgba(0,0,0,.125)); +} + +// Navbar button for toggling navbar items in responsive layouts +// These definitions need to come after '.navbar .btn' +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + .buttonBackground(darken(@navbarBackgroundHighlight, 5%), darken(@navbarBackground, 5%)); + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)"); +} +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + .border-radius(1px); + .box-shadow(0 1px 0 rgba(0,0,0,.25)); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + + + +// Dropdown menus +// -------------- + +// Menu position and menu carets +.navbar .nav > li > .dropdown-menu { + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: @dropdownBorder; + position: absolute; + top: -7px; + left: 9px; + } + &:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid @dropdownBackground; + position: absolute; + top: -6px; + left: 10px; + } +} +// Menu position and menu caret support for dropups via extra dropup class +.navbar-fixed-bottom .nav > li > .dropdown-menu { + &:before { + border-top: 7px solid #ccc; + border-top-color: @dropdownBorder; + border-bottom: 0; + bottom: -7px; + top: auto; + } + &:after { + border-top: 6px solid @dropdownBackground; + border-bottom: 0; + bottom: -6px; + top: auto; + } +} + +// Caret should match text color on hover/focus +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: @navbarLinkColorHover; + border-bottom-color: @navbarLinkColorHover; +} + +// Remove background color from open dropdown +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: @navbarLinkBackgroundActive; + color: @navbarLinkColorActive; +} +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: @navbarLinkColor; + border-bottom-color: @navbarLinkColor; +} +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: @navbarLinkColorActive; + border-bottom-color: @navbarLinkColorActive; +} + +// Right aligned menus need alt position +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + left: auto; + right: 0; + &:before { + left: auto; + right: 12px; + } + &:after { + left: auto; + right: 13px; + } + .dropdown-menu { + left: auto; + right: 100%; + margin-left: 0; + margin-right: -1px; + .border-radius(6px 0 6px 6px); + } +} + + +// Inverted navbar +// ------------------------- + +.navbar-inverse { + + .navbar-inner { + #gradient > .vertical(@navbarInverseBackgroundHighlight, @navbarInverseBackground); + border-color: @navbarInverseBorder; + } + + .brand, + .nav > li > a { + color: @navbarInverseLinkColor; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + &:hover, + &:focus { + color: @navbarInverseLinkColorHover; + } + } + + .brand { + color: @navbarInverseBrandColor; + } + + .navbar-text { + color: @navbarInverseText; + } + + .nav > li > a:focus, + .nav > li > a:hover { + background-color: @navbarInverseLinkBackgroundHover; + color: @navbarInverseLinkColorHover; + } + + .nav .active > a, + .nav .active > a:hover, + .nav .active > a:focus { + color: @navbarInverseLinkColorActive; + background-color: @navbarInverseLinkBackgroundActive; + } + + // Inline text links + .navbar-link { + color: @navbarInverseLinkColor; + &:hover, + &:focus { + color: @navbarInverseLinkColorHover; + } + } + + // Dividers in navbar + .divider-vertical { + border-left-color: @navbarInverseBackground; + border-right-color: @navbarInverseBackgroundHighlight; + } + + // Dropdowns + .nav li.dropdown.open > .dropdown-toggle, + .nav li.dropdown.active > .dropdown-toggle, + .nav li.dropdown.open.active > .dropdown-toggle { + background-color: @navbarInverseLinkBackgroundActive; + color: @navbarInverseLinkColorActive; + } + .nav li.dropdown > a:hover .caret, + .nav li.dropdown > a:focus .caret { + border-top-color: @navbarInverseLinkColorActive; + border-bottom-color: @navbarInverseLinkColorActive; + } + .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: @navbarInverseLinkColor; + border-bottom-color: @navbarInverseLinkColor; + } + .nav li.dropdown.open > .dropdown-toggle .caret, + .nav li.dropdown.active > .dropdown-toggle .caret, + .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: @navbarInverseLinkColorActive; + border-bottom-color: @navbarInverseLinkColorActive; + } + + // Navbar search + .navbar-search { + .search-query { + color: @white; + background-color: @navbarInverseSearchBackground; + border-color: @navbarInverseSearchBorder; + .box-shadow(~"inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15)"); + .transition(none); + .placeholder(@navbarInverseSearchPlaceholderColor); + + // Focus states (we use .focused since IE7-8 and down doesn't support :focus) + &:focus, + &.focused { + padding: 5px 15px; + color: @grayDark; + text-shadow: 0 1px 0 @white; + background-color: @navbarInverseSearchBackgroundFocus; + border: 0; + .box-shadow(0 0 3px rgba(0,0,0,.15)); + outline: 0; + } + } + } + + // Navbar collapse button + .btn-navbar { + .buttonBackground(darken(@navbarInverseBackgroundHighlight, 5%), darken(@navbarInverseBackground, 5%)); + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/navs.less b/openid-connect-server-webapp/src/main/webapp/less/navs.less new file mode 100644 index 000000000..01cd805bd --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/navs.less @@ -0,0 +1,409 @@ +// +// Navs +// -------------------------------------------------- + + +// BASE CLASS +// ---------- + +.nav { + margin-left: 0; + margin-bottom: @baseLineHeight; + list-style: none; +} + +// Make links block level +.nav > li > a { + display: block; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: @grayLighter; +} + +// Prevent IE8 from misplacing imgs +// See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989 +.nav > li > a > img { + max-width: none; +} + +// Redeclare pull classes because of specifity +.nav > .pull-right { + float: right; +} + +// Nav headers (for dropdowns and lists) +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: @baseLineHeight; + color: @grayLight; + text-shadow: 0 1px 0 rgba(255,255,255,.5); + text-transform: uppercase; +} +// Space them out when they follow another list item (link) +.nav li + .nav-header { + margin-top: 9px; +} + + + +// NAV LIST +// -------- + +.nav-list { + padding-left: 15px; + padding-right: 15px; + margin-bottom: 0; +} +.nav-list > li > a, +.nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255,255,255,.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: @white; + text-shadow: 0 -1px 0 rgba(0,0,0,.2); + background-color: @linkColor; +} +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} +// Dividers (basically an hr) within the dropdown +.nav-list .divider { + .nav-divider(); +} + + + +// TABS AND PILLS +// ------------- + +// Common styles +.nav-tabs, +.nav-pills { + .clearfix(); +} +.nav-tabs > li, +.nav-pills > li { + float: left; +} +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; // keeps the overall height an even number +} + +// TABS +// ---- + +// Give the tabs something to sit on +.nav-tabs { + border-bottom: 1px solid #ddd; +} +// Make the list-items overlay the bottom border +.nav-tabs > li { + margin-bottom: -1px; +} +// Actual tabs (as links) +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: @baseLineHeight; + border: 1px solid transparent; + .border-radius(4px 4px 0 0); + &:hover, + &:focus { + border-color: @grayLighter @grayLighter #ddd; + } +} +// Active state, and it's :hover/:focus to override normal :hover/:focus +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: @gray; + background-color: @bodyBackground; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} + + +// PILLS +// ----- + +// Links rendered as pills +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + .border-radius(5px); +} + +// Active state +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: @white; + background-color: @linkColor; +} + + + +// STACKED NAV +// ----------- + +// Stacked tabs and pills +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; // no need for the gap between nav items +} + +// Tabs +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + .border-radius(0); +} +.nav-tabs.nav-stacked > li:first-child > a { + .border-top-radius(4px); +} +.nav-tabs.nav-stacked > li:last-child > a { + .border-bottom-radius(4px); +} +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + border-color: #ddd; + z-index: 2; +} + +// Pills +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; // decrease margin to match sizing of stacked tabs +} + + + +// DROPDOWNS +// --------- + +.nav-tabs .dropdown-menu { + .border-radius(0 0 6px 6px); // remove the top rounded corners here since there is a hard edge above the menu +} +.nav-pills .dropdown-menu { + .border-radius(6px); // make rounded corners match the pills +} + +// Default dropdown links +// ------------------------- +// Make carets use linkColor to start +.nav .dropdown-toggle .caret { + border-top-color: @linkColor; + border-bottom-color: @linkColor; + margin-top: 6px; +} +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: @linkColorHover; + border-bottom-color: @linkColorHover; +} +/* move down carets for tabs */ +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +// Active dropdown links +// ------------------------- +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: @gray; + border-bottom-color: @gray; +} + +// Active:hover/:focus dropdown links +// ------------------------- +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +// Open dropdowns +// ------------------------- +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: @white; + background-color: @grayLight; + border-color: @grayLight; +} +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: @white; + border-bottom-color: @white; + .opacity(100); +} + +// Dropdowns in stacked tabs +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: @grayLight; +} + + + +// TABBABLE +// -------- + + +// COMMON STYLES +// ------------- + +// Clear any floats +.tabbable { + .clearfix(); +} +.tab-content { + overflow: auto; // prevent content from running below tabs +} + +// Remove border on bottom, left, right +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +// Show/hide tabbable areas +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} +.tab-content > .active, +.pill-content > .active { + display: block; +} + + +// BOTTOM +// ------ + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below > .nav-tabs > li > a { + .border-radius(0 0 4px 4px); + &:hover, + &:focus { + border-bottom-color: transparent; + border-top-color: #ddd; + } +} +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +// LEFT & RIGHT +// ------------ + +// Common styles +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +// Tabs on the left +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + .border-radius(4px 0 0 4px); +} +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: @grayLighter #ddd @grayLighter @grayLighter; +} +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: @white; +} + +// Tabs on the right +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + .border-radius(0 4px 4px 0); +} +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: @grayLighter @grayLighter @grayLighter #ddd; +} +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: @white; +} + + + +// DISABLED STATES +// --------------- + +// Gray out text +.nav > .disabled > a { + color: @grayLight; +} +// Nuke hover/focus effects +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + cursor: default; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/pager.less b/openid-connect-server-webapp/src/main/webapp/less/pager.less new file mode 100644 index 000000000..147618829 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/pager.less @@ -0,0 +1,43 @@ +// +// Pager pagination +// -------------------------------------------------- + + +.pager { + margin: @baseLineHeight 0; + list-style: none; + text-align: center; + .clearfix(); +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + .border-radius(15px); +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: @grayLight; + background-color: #fff; + cursor: default; +} \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/less/pagination.less b/openid-connect-server-webapp/src/main/webapp/less/pagination.less new file mode 100644 index 000000000..a789db2d2 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/pagination.less @@ -0,0 +1,123 @@ +// +// Pagination (multiple pages) +// -------------------------------------------------- + +// Space out pagination from surrounding content +.pagination { + margin: @baseLineHeight 0; +} + +.pagination ul { + // Allow for text-based alignment + display: inline-block; + .ie7-inline-block(); + // Reset default ul styles + margin-left: 0; + margin-bottom: 0; + // Visuals + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 2px rgba(0,0,0,.05)); +} +.pagination ul > li { + display: inline; // Remove list-style and block-level defaults +} +.pagination ul > li > a, +.pagination ul > li > span { + float: left; // Collapse white-space + padding: 4px 12px; + line-height: @baseLineHeight; + text-decoration: none; + background-color: @paginationBackground; + border: 1px solid @paginationBorder; + border-left-width: 0; +} +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: @paginationActiveBackground; +} +.pagination ul > .active > a, +.pagination ul > .active > span { + color: @grayLight; + cursor: default; +} +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: @grayLight; + background-color: transparent; + cursor: default; +} +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + .border-left-radius(@baseBorderRadius); +} +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + .border-right-radius(@baseBorderRadius); +} + + +// Alignment +// -------------------------------------------------- + +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} + + +// Sizing +// -------------------------------------------------- + +// Large +.pagination-large { + ul > li > a, + ul > li > span { + padding: @paddingLarge; + font-size: @fontSizeLarge; + } + ul > li:first-child > a, + ul > li:first-child > span { + .border-left-radius(@borderRadiusLarge); + } + ul > li:last-child > a, + ul > li:last-child > span { + .border-right-radius(@borderRadiusLarge); + } +} + +// Small and mini +.pagination-mini, +.pagination-small { + ul > li:first-child > a, + ul > li:first-child > span { + .border-left-radius(@borderRadiusSmall); + } + ul > li:last-child > a, + ul > li:last-child > span { + .border-right-radius(@borderRadiusSmall); + } +} + +// Small +.pagination-small { + ul > li > a, + ul > li > span { + padding: @paddingSmall; + font-size: @fontSizeSmall; + } +} +// Mini +.pagination-mini { + ul > li > a, + ul > li > span { + padding: @paddingMini; + font-size: @fontSizeMini; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/popovers.less b/openid-connect-server-webapp/src/main/webapp/less/popovers.less new file mode 100644 index 000000000..aae35c8cd --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/popovers.less @@ -0,0 +1,133 @@ +// +// Popovers +// -------------------------------------------------- + + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: @zindexPopover; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; // Reset given new insertion method + background-color: @popoverBackground; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.2); + .border-radius(6px); + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + + // Overrides for proper insertion + white-space: normal; + + // Offset the popover to account for the popover arrow + &.top { margin-top: -10px; } + &.right { margin-left: 10px; } + &.bottom { margin-top: 10px; } + &.left { margin-left: -10px; } +} + +.popover-title { + margin: 0; // reset heading margin + padding: 8px 14px; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: @popoverTitleBackground; + border-bottom: 1px solid darken(@popoverTitleBackground, 5%); + .border-radius(5px 5px 0 0); + + &:empty { + display: none; + } +} + +.popover-content { + padding: 9px 14px; +} + +// Arrows +// +// .arrow is outer, .arrow:after is inner + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: @popoverArrowOuterWidth; +} +.popover .arrow:after { + border-width: @popoverArrowWidth; + content: ""; +} + +.popover { + &.top .arrow { + left: 50%; + margin-left: -@popoverArrowOuterWidth; + border-bottom-width: 0; + border-top-color: #999; // IE8 fallback + border-top-color: @popoverArrowOuterColor; + bottom: -@popoverArrowOuterWidth; + &:after { + bottom: 1px; + margin-left: -@popoverArrowWidth; + border-bottom-width: 0; + border-top-color: @popoverArrowColor; + } + } + &.right .arrow { + top: 50%; + left: -@popoverArrowOuterWidth; + margin-top: -@popoverArrowOuterWidth; + border-left-width: 0; + border-right-color: #999; // IE8 fallback + border-right-color: @popoverArrowOuterColor; + &:after { + left: 1px; + bottom: -@popoverArrowWidth; + border-left-width: 0; + border-right-color: @popoverArrowColor; + } + } + &.bottom .arrow { + left: 50%; + margin-left: -@popoverArrowOuterWidth; + border-top-width: 0; + border-bottom-color: #999; // IE8 fallback + border-bottom-color: @popoverArrowOuterColor; + top: -@popoverArrowOuterWidth; + &:after { + top: 1px; + margin-left: -@popoverArrowWidth; + border-top-width: 0; + border-bottom-color: @popoverArrowColor; + } + } + + &.left .arrow { + top: 50%; + right: -@popoverArrowOuterWidth; + margin-top: -@popoverArrowOuterWidth; + border-right-width: 0; + border-left-color: #999; // IE8 fallback + border-left-color: @popoverArrowOuterColor; + &:after { + right: 1px; + border-right-width: 0; + border-left-color: @popoverArrowColor; + bottom: -@popoverArrowWidth; + } + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/progress-bars.less b/openid-connect-server-webapp/src/main/webapp/less/progress-bars.less new file mode 100644 index 000000000..5e0c3dda0 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/progress-bars.less @@ -0,0 +1,122 @@ +// +// Progress bars +// -------------------------------------------------- + + +// ANIMATIONS +// ---------- + +// Webkit +@-webkit-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Firefox +@-moz-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// IE9 +@-ms-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Opera +@-o-keyframes progress-bar-stripes { + from { background-position: 0 0; } + to { background-position: 40px 0; } +} + +// Spec +@keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + + + +// THE BARS +// -------- + +// Outer container +.progress { + overflow: hidden; + height: @baseLineHeight; + margin-bottom: @baseLineHeight; + #gradient > .vertical(#f5f5f5, #f9f9f9); + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); + .border-radius(@baseBorderRadius); +} + +// Bar of progress +.progress .bar { + width: 0%; + height: 100%; + color: @white; + float: left; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + #gradient > .vertical(#149bdf, #0480be); + .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); + .box-sizing(border-box); + .transition(width .6s ease); +} +.progress .bar + .bar { + .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)"); +} + +// Striped bars +.progress-striped .bar { + #gradient > .striped(#149bdf); + .background-size(40px 40px); +} + +// Call animation for the active one +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + + + +// COLORS +// ------ + +// Danger (red) +.progress-danger .bar, .progress .bar-danger { + #gradient > .vertical(#ee5f5b, #c43c35); +} +.progress-danger.progress-striped .bar, .progress-striped .bar-danger { + #gradient > .striped(#ee5f5b); +} + +// Success (green) +.progress-success .bar, .progress .bar-success { + #gradient > .vertical(#62c462, #57a957); +} +.progress-success.progress-striped .bar, .progress-striped .bar-success { + #gradient > .striped(#62c462); +} + +// Info (teal) +.progress-info .bar, .progress .bar-info { + #gradient > .vertical(#5bc0de, #339bb9); +} +.progress-info.progress-striped .bar, .progress-striped .bar-info { + #gradient > .striped(#5bc0de); +} + +// Warning (orange) +.progress-warning .bar, .progress .bar-warning { + #gradient > .vertical(lighten(@orange, 15%), @orange); +} +.progress-warning.progress-striped .bar, .progress-striped .bar-warning { + #gradient > .striped(lighten(@orange, 15%)); +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/reset.less b/openid-connect-server-webapp/src/main/webapp/less/reset.less new file mode 100644 index 000000000..4806bd5e5 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/reset.less @@ -0,0 +1,216 @@ +// +// Reset CSS +// Adapted from http://github.com/necolas/normalize.css +// -------------------------------------------------- + + +// Display in IE6-9 and FF3 +// ------------------------- + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +// Display block in IE6-9 and FF3 +// ------------------------- + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +// Prevents modern browsers from displaying 'audio' without controls +// ------------------------- + +audio:not([controls]) { + display: none; +} + +// Base settings +// ------------------------- + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +// Focus states +a:focus { + .tab-focus(); +} +// Hover & Active +a:hover, +a:active { + outline: 0; +} + +// Prevents sub and sup affecting line-height in all browsers +// ------------------------- + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} + +// Img border in a's and image quality +// ------------------------- + +img { + /* Responsive images (ensure images don't scale beyond their parents) */ + max-width: 100%; /* Part 1: Set a maxium relative to the parent */ + width: auto\9; /* IE7-8 need help adjusting responsive images */ + height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */ + + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +// Prevent max-width from affecting Google Maps +#map_canvas img, +.google-maps img { + max-width: none; +} + +// Forms +// ------------------------- + +// Font size in all browsers, margin changes, misc consistency +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, +input { + *overflow: visible; // Inner spacing ie IE6/7 + line-height: normal; // FF3/4 have !important on line-height in UA stylesheet +} +button::-moz-focus-inner, +input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 + padding: 0; + border: 0; +} +button, +html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS. + cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. +} +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. +} +input[type="search"] { // Appearance in Safari/Chrome + .box-sizing(content-box); + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 +} +textarea { + overflow: auto; // Remove vertical scrollbar in IE6-9 + vertical-align: top; // Readability and alignment cross-browser +} + + +// Printing +// ------------------------- +// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css + +@media print { + + * { + text-shadow: none !important; + color: #000 !important; // Black prints faster: h5bp.com/s + background: transparent !important; + box-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + // Don't show links for images, or javascript/internal links + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; // h5bp.com/t + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page { + margin: 0.5cm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/responsive-1200px-min.less b/openid-connect-server-webapp/src/main/webapp/less/responsive-1200px-min.less new file mode 100644 index 000000000..4f35ba6ca --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/responsive-1200px-min.less @@ -0,0 +1,28 @@ +// +// Responsive: Large desktop and up +// -------------------------------------------------- + + +@media (min-width: 1200px) { + + // Fixed grid + #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); + + // Fluid grid + #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); + + // Input grid + #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); + + // Thumbnails + .thumbnails { + margin-left: -@gridGutterWidth1200; + } + .thumbnails > li { + margin-left: @gridGutterWidth1200; + } + .row-fluid .thumbnails { + margin-left: 0; + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/responsive-767px-max.less b/openid-connect-server-webapp/src/main/webapp/less/responsive-767px-max.less new file mode 100644 index 000000000..128f4ce30 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/responsive-767px-max.less @@ -0,0 +1,193 @@ +// +// Responsive: Landscape phone to desktop/tablet +// -------------------------------------------------- + + +@media (max-width: 767px) { + + // Padding to set content in a bit + body { + padding-left: 20px; + padding-right: 20px; + } + // Negative indent the now static "fixed" navbar + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-left: -20px; + margin-right: -20px; + } + // Remove padding on container given explicit padding set on body + .container-fluid { + padding: 0; + } + + // TYPOGRAPHY + // ---------- + // Reset horizontal dl + .dl-horizontal { + dt { + float: none; + clear: none; + width: auto; + text-align: left; + } + dd { + margin-left: 0; + } + } + + // GRID & CONTAINERS + // ----------------- + // Remove width from containers + .container { + width: auto; + } + // Fluid rows + .row-fluid { + width: 100%; + } + // Undo negative margin on rows and thumbnails + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; // Reset the default margin for all li elements when no .span* classes are present + } + // Make all grid-sized elements block level again + [class*="span"], + .uneditable-input[class*="span"], // Makes uneditable inputs full-width when using grid sizing + .row-fluid [class*="span"] { + float: none; + display: block; + width: 100%; + margin-left: 0; + .box-sizing(border-box); + } + .span12, + .row-fluid .span12 { + width: 100%; + .box-sizing(border-box); + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + + // FORM FIELDS + // ----------- + // Make span* classes full width + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + .input-block-level(); + } + // But don't let it screw up prepend/append inputs + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; // redeclare so they don't wrap to new lines + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + + // Modals + .modal { + position: fixed; + top: 20px; + left: 20px; + right: 20px; + width: auto; + margin: 0; + &.fade { top: -100px; } + &.fade.in { top: 20px; } + } + +} + + + +// UP TO LANDSCAPE PHONE +// --------------------- + +@media (max-width: 480px) { + + // Smooth out the collapsing/expanding nav + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); // activate the GPU + } + + // Block level the page header small tag for readability + .page-header h1 small { + display: block; + line-height: @baseLineHeight; + } + + // Update checkboxes for iOS + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + + // Remove the horizontal form styles + .form-horizontal { + .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + // Move over all input controls and content + .controls { + margin-left: 0; + } + // Move the options list down to align with labels + .control-list { + padding-top: 0; // has to be padding because margin collaspes + } + // Move over buttons in .form-actions to align with .controls + .form-actions { + padding-left: 10px; + padding-right: 10px; + } + } + + // Medias + // Reset float and spacing to stack + .media .pull-left, + .media .pull-right { + float: none; + display: block; + margin-bottom: 10px; + } + // Remove side margins since we stack instead of indent + .media-object { + margin-right: 0; + margin-left: 0; + } + + // Modals + .modal { + top: 10px; + left: 10px; + right: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + + // Carousel + .carousel-caption { + position: static; + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/responsive-768px-979px.less b/openid-connect-server-webapp/src/main/webapp/less/responsive-768px-979px.less new file mode 100644 index 000000000..8e8c486a0 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/responsive-768px-979px.less @@ -0,0 +1,19 @@ +// +// Responsive: Tablet to desktop +// -------------------------------------------------- + + +@media (min-width: 768px) and (max-width: 979px) { + + // Fixed grid + #grid > .core(@gridColumnWidth768, @gridGutterWidth768); + + // Fluid grid + #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); + + // Input grid + #grid > .input(@gridColumnWidth768, @gridGutterWidth768); + + // No need to reset .thumbnails here since it's the same @gridGutterWidth + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/responsive-navbar.less b/openid-connect-server-webapp/src/main/webapp/less/responsive-navbar.less new file mode 100644 index 000000000..21cd3ba67 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/responsive-navbar.less @@ -0,0 +1,189 @@ +// +// Responsive: Navbar +// -------------------------------------------------- + + +// TABLETS AND BELOW +// ----------------- +@media (max-width: @navbarCollapseWidth) { + + // UNFIX THE TOPBAR + // ---------------- + // Remove any padding from the body + body { + padding-top: 0; + } + // Unfix the navbars + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: @baseLineHeight; + } + .navbar-fixed-bottom { + margin-top: @baseLineHeight; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + // Account for brand name + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + + // COLLAPSIBLE NAVBAR + // ------------------ + // Nav collapse clears brand + .nav-collapse { + clear: both; + } + // Block-level the nav + .nav-collapse .nav { + float: none; + margin: 0 0 (@baseLineHeight / 2); + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: @navbarText; + text-shadow: none; + } + // Nav and dropdown links in navbar + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: @navbarLinkColor; + .border-radius(3px); + } + // Buttons + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + .border-radius(@baseBorderRadius); + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: @navbarBackground; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: @navbarInverseLinkColor; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: @navbarInverseBackground; + } + // Buttons in the navbar + .nav-collapse.in .btn-group { + margin-top: 5px; + padding: 0; + } + // Dropdowns in the navbar + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: none; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + .border-radius(0); + .box-shadow(none); + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu { + &:before, + &:after { + display: none; + } + } + // Forms in navbar + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: (@baseLineHeight / 2) 15px; + margin: (@baseLineHeight / 2) 0; + border-top: 1px solid @navbarBackground; + border-bottom: 1px solid @navbarBackground; + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)"); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: @navbarInverseBackground; + border-bottom-color: @navbarInverseBackground; + } + // Pull right (secondary) nav content + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + // Hide everything in the navbar save .brand and toggle button */ + .nav-collapse, + .nav-collapse.collapse { + overflow: hidden; + height: 0; + } + // Navbar button + .navbar .btn-navbar { + display: block; + } + + // STATIC NAVBAR + // ------------- + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + + +} + + +// DEFAULT DESKTOP +// --------------- + +@media (min-width: @navbarCollapseDesktopWidth) { + + // Required to make the collapsing navbar work on regular desktops + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/responsive-utilities.less b/openid-connect-server-webapp/src/main/webapp/less/responsive-utilities.less new file mode 100644 index 000000000..bf43e8ef7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/responsive-utilities.less @@ -0,0 +1,59 @@ +// +// Responsive: Utility classes +// -------------------------------------------------- + + +// IE10 Metro responsive +// Required for Windows 8 Metro split-screen snapping with IE10 +// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ +@-ms-viewport{ + width: device-width; +} + +// Hide from screenreaders and browsers +// Credit: HTML5 Boilerplate +.hidden { + display: none; + visibility: hidden; +} + +// Visibility utilities + +// For desktops +.visible-phone { display: none !important; } +.visible-tablet { display: none !important; } +.hidden-phone { } +.hidden-tablet { } +.hidden-desktop { display: none !important; } +.visible-desktop { display: inherit !important; } + +// Tablets & small desktops only +@media (min-width: 768px) and (max-width: 979px) { + // Hide everything else + .hidden-desktop { display: inherit !important; } + .visible-desktop { display: none !important ; } + // Show + .visible-tablet { display: inherit !important; } + // Hide + .hidden-tablet { display: none !important; } +} + +// Phones only +@media (max-width: 767px) { + // Hide everything else + .hidden-desktop { display: inherit !important; } + .visible-desktop { display: none !important; } + // Show + .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior + // Hide + .hidden-phone { display: none !important; } +} + +// Print utilities +.visible-print { display: none !important; } +.hidden-print { } + +@media print { + .visible-print { display: inherit !important; } + .hidden-print { display: none !important; } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/scaffolding.less b/openid-connect-server-webapp/src/main/webapp/less/scaffolding.less new file mode 100644 index 000000000..f17e8cadb --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/scaffolding.less @@ -0,0 +1,53 @@ +// +// Scaffolding +// -------------------------------------------------- + + +// Body reset +// ------------------------- + +body { + margin: 0; + font-family: @baseFontFamily; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @textColor; + background-color: @bodyBackground; +} + + +// Links +// ------------------------- + +a { + color: @linkColor; + text-decoration: none; +} +a:hover, +a:focus { + color: @linkColorHover; + text-decoration: underline; +} + + +// Images +// ------------------------- + +// Rounded corners +.img-rounded { + .border-radius(6px); +} + +// Add polaroid-esque trim +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.2); + .box-shadow(0 1px 3px rgba(0,0,0,.1)); +} + +// Perfect circle +.img-circle { + .border-radius(500px); // crank the border-radius so it works with most reasonably sized images +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/sprites.less b/openid-connect-server-webapp/src/main/webapp/less/sprites.less new file mode 100644 index 000000000..1812bf71a --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/sprites.less @@ -0,0 +1,197 @@ +// +// Sprites +// -------------------------------------------------- + + +// ICONS +// ----- + +// All icons receive the styles of the tag with a base class +// of .i and are then given a unique class to add width, height, +// and background-position. Your resulting HTML will look like +// . + +// For the white version of the icons, just add the .icon-white class: +// + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + .ie7-restore-right-whitespace(); + line-height: 14px; + vertical-align: text-top; + background-image: url("@{iconSpritePath}"); + background-position: 14px 14px; + background-repeat: no-repeat; + margin-top: 1px; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("@{iconWhiteSpritePath}"); +} + +.icon-glass { background-position: 0 0; } +.icon-music { background-position: -24px 0; } +.icon-search { background-position: -48px 0; } +.icon-envelope { background-position: -72px 0; } +.icon-heart { background-position: -96px 0; } +.icon-star { background-position: -120px 0; } +.icon-star-empty { background-position: -144px 0; } +.icon-user { background-position: -168px 0; } +.icon-film { background-position: -192px 0; } +.icon-th-large { background-position: -216px 0; } +.icon-th { background-position: -240px 0; } +.icon-th-list { background-position: -264px 0; } +.icon-ok { background-position: -288px 0; } +.icon-remove { background-position: -312px 0; } +.icon-zoom-in { background-position: -336px 0; } +.icon-zoom-out { background-position: -360px 0; } +.icon-off { background-position: -384px 0; } +.icon-signal { background-position: -408px 0; } +.icon-cog { background-position: -432px 0; } +.icon-trash { background-position: -456px 0; } + +.icon-home { background-position: 0 -24px; } +.icon-file { background-position: -24px -24px; } +.icon-time { background-position: -48px -24px; } +.icon-road { background-position: -72px -24px; } +.icon-download-alt { background-position: -96px -24px; } +.icon-download { background-position: -120px -24px; } +.icon-upload { background-position: -144px -24px; } +.icon-inbox { background-position: -168px -24px; } +.icon-play-circle { background-position: -192px -24px; } +.icon-repeat { background-position: -216px -24px; } +.icon-refresh { background-position: -240px -24px; } +.icon-list-alt { background-position: -264px -24px; } +.icon-lock { background-position: -287px -24px; } // 1px off +.icon-flag { background-position: -312px -24px; } +.icon-headphones { background-position: -336px -24px; } +.icon-volume-off { background-position: -360px -24px; } +.icon-volume-down { background-position: -384px -24px; } +.icon-volume-up { background-position: -408px -24px; } +.icon-qrcode { background-position: -432px -24px; } +.icon-barcode { background-position: -456px -24px; } + +.icon-tag { background-position: 0 -48px; } +.icon-tags { background-position: -25px -48px; } // 1px off +.icon-book { background-position: -48px -48px; } +.icon-bookmark { background-position: -72px -48px; } +.icon-print { background-position: -96px -48px; } +.icon-camera { background-position: -120px -48px; } +.icon-font { background-position: -144px -48px; } +.icon-bold { background-position: -167px -48px; } // 1px off +.icon-italic { background-position: -192px -48px; } +.icon-text-height { background-position: -216px -48px; } +.icon-text-width { background-position: -240px -48px; } +.icon-align-left { background-position: -264px -48px; } +.icon-align-center { background-position: -288px -48px; } +.icon-align-right { background-position: -312px -48px; } +.icon-align-justify { background-position: -336px -48px; } +.icon-list { background-position: -360px -48px; } +.icon-indent-left { background-position: -384px -48px; } +.icon-indent-right { background-position: -408px -48px; } +.icon-facetime-video { background-position: -432px -48px; } +.icon-picture { background-position: -456px -48px; } + +.icon-pencil { background-position: 0 -72px; } +.icon-map-marker { background-position: -24px -72px; } +.icon-adjust { background-position: -48px -72px; } +.icon-tint { background-position: -72px -72px; } +.icon-edit { background-position: -96px -72px; } +.icon-share { background-position: -120px -72px; } +.icon-check { background-position: -144px -72px; } +.icon-move { background-position: -168px -72px; } +.icon-step-backward { background-position: -192px -72px; } +.icon-fast-backward { background-position: -216px -72px; } +.icon-backward { background-position: -240px -72px; } +.icon-play { background-position: -264px -72px; } +.icon-pause { background-position: -288px -72px; } +.icon-stop { background-position: -312px -72px; } +.icon-forward { background-position: -336px -72px; } +.icon-fast-forward { background-position: -360px -72px; } +.icon-step-forward { background-position: -384px -72px; } +.icon-eject { background-position: -408px -72px; } +.icon-chevron-left { background-position: -432px -72px; } +.icon-chevron-right { background-position: -456px -72px; } + +.icon-plus-sign { background-position: 0 -96px; } +.icon-minus-sign { background-position: -24px -96px; } +.icon-remove-sign { background-position: -48px -96px; } +.icon-ok-sign { background-position: -72px -96px; } +.icon-question-sign { background-position: -96px -96px; } +.icon-info-sign { background-position: -120px -96px; } +.icon-screenshot { background-position: -144px -96px; } +.icon-remove-circle { background-position: -168px -96px; } +.icon-ok-circle { background-position: -192px -96px; } +.icon-ban-circle { background-position: -216px -96px; } +.icon-arrow-left { background-position: -240px -96px; } +.icon-arrow-right { background-position: -264px -96px; } +.icon-arrow-up { background-position: -289px -96px; } // 1px off +.icon-arrow-down { background-position: -312px -96px; } +.icon-share-alt { background-position: -336px -96px; } +.icon-resize-full { background-position: -360px -96px; } +.icon-resize-small { background-position: -384px -96px; } +.icon-plus { background-position: -408px -96px; } +.icon-minus { background-position: -433px -96px; } +.icon-asterisk { background-position: -456px -96px; } + +.icon-exclamation-sign { background-position: 0 -120px; } +.icon-gift { background-position: -24px -120px; } +.icon-leaf { background-position: -48px -120px; } +.icon-fire { background-position: -72px -120px; } +.icon-eye-open { background-position: -96px -120px; } +.icon-eye-close { background-position: -120px -120px; } +.icon-warning-sign { background-position: -144px -120px; } +.icon-plane { background-position: -168px -120px; } +.icon-calendar { background-position: -192px -120px; } +.icon-random { background-position: -216px -120px; width: 16px; } +.icon-comment { background-position: -240px -120px; } +.icon-magnet { background-position: -264px -120px; } +.icon-chevron-up { background-position: -288px -120px; } +.icon-chevron-down { background-position: -313px -119px; } // 1px, 1px off +.icon-retweet { background-position: -336px -120px; } +.icon-shopping-cart { background-position: -360px -120px; } +.icon-folder-close { background-position: -384px -120px; width: 16px; } +.icon-folder-open { background-position: -408px -120px; width: 16px; } +.icon-resize-vertical { background-position: -432px -119px; } // 1px, 1px off +.icon-resize-horizontal { background-position: -456px -118px; } // 1px, 2px off + +.icon-hdd { background-position: 0 -144px; } +.icon-bullhorn { background-position: -24px -144px; } +.icon-bell { background-position: -48px -144px; } +.icon-certificate { background-position: -72px -144px; } +.icon-thumbs-up { background-position: -96px -144px; } +.icon-thumbs-down { background-position: -120px -144px; } +.icon-hand-right { background-position: -144px -144px; } +.icon-hand-left { background-position: -168px -144px; } +.icon-hand-up { background-position: -192px -144px; } +.icon-hand-down { background-position: -216px -144px; } +.icon-circle-arrow-right { background-position: -240px -144px; } +.icon-circle-arrow-left { background-position: -264px -144px; } +.icon-circle-arrow-up { background-position: -288px -144px; } +.icon-circle-arrow-down { background-position: -312px -144px; } +.icon-globe { background-position: -336px -144px; } +.icon-wrench { background-position: -360px -144px; } +.icon-tasks { background-position: -384px -144px; } +.icon-filter { background-position: -408px -144px; } +.icon-briefcase { background-position: -432px -144px; } +.icon-fullscreen { background-position: -456px -144px; } diff --git a/openid-connect-server-webapp/src/main/webapp/less/tables.less b/openid-connect-server-webapp/src/main/webapp/less/tables.less new file mode 100644 index 000000000..0e35271e1 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/tables.less @@ -0,0 +1,244 @@ +// +// Tables +// -------------------------------------------------- + + +// BASE TABLES +// ----------------- + +table { + max-width: 100%; + background-color: @tableBackground; + border-collapse: collapse; + border-spacing: 0; +} + +// BASELINE STYLES +// --------------- + +.table { + width: 100%; + margin-bottom: @baseLineHeight; + // Cells + th, + td { + padding: 8px; + line-height: @baseLineHeight; + text-align: left; + vertical-align: top; + border-top: 1px solid @tableBorder; + } + th { + font-weight: bold; + } + // Bottom align for column headings + thead th { + vertical-align: bottom; + } + // Remove top border from thead by default + caption + thead tr:first-child th, + caption + thead tr:first-child td, + colgroup + thead tr:first-child th, + colgroup + thead tr:first-child td, + thead:first-child tr:first-child th, + thead:first-child tr:first-child td { + border-top: 0; + } + // Account for multiple tbody instances + tbody + tbody { + border-top: 2px solid @tableBorder; + } + + // Nesting + .table { + background-color: @bodyBackground; + } +} + + + +// CONDENSED TABLE W/ HALF PADDING +// ------------------------------- + +.table-condensed { + th, + td { + padding: 4px 5px; + } +} + + +// BORDERED VERSION +// ---------------- + +.table-bordered { + border: 1px solid @tableBorder; + border-collapse: separate; // Done so we can round those corners! + *border-collapse: collapse; // IE7 can't round corners anyway + border-left: 0; + .border-radius(@baseBorderRadius); + th, + td { + border-left: 1px solid @tableBorder; + } + // Prevent a double border + caption + thead tr:first-child th, + caption + tbody tr:first-child th, + caption + tbody tr:first-child td, + colgroup + thead tr:first-child th, + colgroup + tbody tr:first-child th, + colgroup + tbody tr:first-child td, + thead:first-child tr:first-child th, + tbody:first-child tr:first-child th, + tbody:first-child tr:first-child td { + border-top: 0; + } + // For first th/td in the first row in the first thead or tbody + thead:first-child tr:first-child > th:first-child, + tbody:first-child tr:first-child > td:first-child, + tbody:first-child tr:first-child > th:first-child { + .border-top-left-radius(@baseBorderRadius); + } + // For last th/td in the first row in the first thead or tbody + thead:first-child tr:first-child > th:last-child, + tbody:first-child tr:first-child > td:last-child, + tbody:first-child tr:first-child > th:last-child { + .border-top-right-radius(@baseBorderRadius); + } + // For first th/td (can be either) in the last row in the last thead, tbody, and tfoot + thead:last-child tr:last-child > th:first-child, + tbody:last-child tr:last-child > td:first-child, + tbody:last-child tr:last-child > th:first-child, + tfoot:last-child tr:last-child > td:first-child, + tfoot:last-child tr:last-child > th:first-child { + .border-bottom-left-radius(@baseBorderRadius); + } + // For last th/td (can be either) in the last row in the last thead, tbody, and tfoot + thead:last-child tr:last-child > th:last-child, + tbody:last-child tr:last-child > td:last-child, + tbody:last-child tr:last-child > th:last-child, + tfoot:last-child tr:last-child > td:last-child, + tfoot:last-child tr:last-child > th:last-child { + .border-bottom-right-radius(@baseBorderRadius); + } + + // Clear border-radius for first and last td in the last row in the last tbody for table with tfoot + tfoot + tbody:last-child tr:last-child td:first-child { + .border-bottom-left-radius(0); + } + tfoot + tbody:last-child tr:last-child td:last-child { + .border-bottom-right-radius(0); + } + + // Special fixes to round the left border on the first td/th + caption + thead tr:first-child th:first-child, + caption + tbody tr:first-child td:first-child, + colgroup + thead tr:first-child th:first-child, + colgroup + tbody tr:first-child td:first-child { + .border-top-left-radius(@baseBorderRadius); + } + caption + thead tr:first-child th:last-child, + caption + tbody tr:first-child td:last-child, + colgroup + thead tr:first-child th:last-child, + colgroup + tbody tr:first-child td:last-child { + .border-top-right-radius(@baseBorderRadius); + } + +} + + + + +// ZEBRA-STRIPING +// -------------- + +// Default zebra-stripe styles (alternating gray and transparent backgrounds) +.table-striped { + tbody { + > tr:nth-child(odd) > td, + > tr:nth-child(odd) > th { + background-color: @tableBackgroundAccent; + } + } +} + + +// HOVER EFFECT +// ------------ +// Placed here since it has to come after the potential zebra striping +.table-hover { + tbody { + tr:hover > td, + tr:hover > th { + background-color: @tableBackgroundHover; + } + } +} + + +// TABLE CELL SIZING +// ----------------- + +// Reset default grid behavior +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; // undo default grid column styles + margin-left: 0; // undo default grid column styles +} + +// Change the column widths to account for td/th padding +.table td, +.table th { + &.span1 { .tableColumns(1); } + &.span2 { .tableColumns(2); } + &.span3 { .tableColumns(3); } + &.span4 { .tableColumns(4); } + &.span5 { .tableColumns(5); } + &.span6 { .tableColumns(6); } + &.span7 { .tableColumns(7); } + &.span8 { .tableColumns(8); } + &.span9 { .tableColumns(9); } + &.span10 { .tableColumns(10); } + &.span11 { .tableColumns(11); } + &.span12 { .tableColumns(12); } +} + + + +// TABLE BACKGROUNDS +// ----------------- +// Exact selectors below required to override .table-striped + +.table tbody tr { + &.success > td { + background-color: @successBackground; + } + &.error > td { + background-color: @errorBackground; + } + &.warning > td { + background-color: @warningBackground; + } + &.info > td { + background-color: @infoBackground; + } +} + +// Hover states for .table-hover +.table-hover tbody tr { + &.success:hover > td { + background-color: darken(@successBackground, 5%); + } + &.error:hover > td { + background-color: darken(@errorBackground, 5%); + } + &.warning:hover > td { + background-color: darken(@warningBackground, 5%); + } + &.info:hover > td { + background-color: darken(@infoBackground, 5%); + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/thumbnails.less b/openid-connect-server-webapp/src/main/webapp/less/thumbnails.less new file mode 100644 index 000000000..4fd07d253 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/thumbnails.less @@ -0,0 +1,53 @@ +// +// Thumbnails +// -------------------------------------------------- + + +// Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files + +// Make wrapper ul behave like the grid +.thumbnails { + margin-left: -@gridGutterWidth; + list-style: none; + .clearfix(); +} +// Fluid rows have no left margin +.row-fluid .thumbnails { + margin-left: 0; +} + +// Float li to make thumbnails appear in a row +.thumbnails > li { + float: left; // Explicity set the float since we don't require .span* classes + margin-bottom: @baseLineHeight; + margin-left: @gridGutterWidth; +} + +// The actual thumbnail (can be `a` or `div`) +.thumbnail { + display: block; + padding: 4px; + line-height: @baseLineHeight; + border: 1px solid #ddd; + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 3px rgba(0,0,0,.055)); + .transition(all .2s ease-in-out); +} +// Add a hover/focus state for linked versions only +a.thumbnail:hover, +a.thumbnail:focus { + border-color: @linkColor; + .box-shadow(0 1px 4px rgba(0,105,214,.25)); +} + +// Images and captions +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; + color: @gray; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/tooltip.less b/openid-connect-server-webapp/src/main/webapp/less/tooltip.less new file mode 100644 index 000000000..83d5f2bd7 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/tooltip.less @@ -0,0 +1,70 @@ +// +// Tooltips +// -------------------------------------------------- + + +// Base class +.tooltip { + position: absolute; + z-index: @zindexTooltip; + display: block; + visibility: visible; + font-size: 11px; + line-height: 1.4; + .opacity(0); + &.in { .opacity(80); } + &.top { margin-top: -3px; padding: 5px 0; } + &.right { margin-left: 3px; padding: 0 5px; } + &.bottom { margin-top: 3px; padding: 5px 0; } + &.left { margin-left: -3px; padding: 0 5px; } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: @tooltipColor; + text-align: center; + text-decoration: none; + background-color: @tooltipBackground; + .border-radius(@baseBorderRadius); +} + +// Arrows +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip { + &.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth @tooltipArrowWidth 0; + border-top-color: @tooltipArrowColor; + } + &.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0; + border-right-color: @tooltipArrowColor; + } + &.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth; + border-left-color: @tooltipArrowColor; + } + &.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -@tooltipArrowWidth; + border-width: 0 @tooltipArrowWidth @tooltipArrowWidth; + border-bottom-color: @tooltipArrowColor; + } +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/type.less b/openid-connect-server-webapp/src/main/webapp/less/type.less new file mode 100644 index 000000000..6a472db49 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/type.less @@ -0,0 +1,247 @@ +// +// Typography +// -------------------------------------------------- + + +// Body text +// ------------------------- + +p { + margin: 0 0 @baseLineHeight / 2; +} +.lead { + margin-bottom: @baseLineHeight; + font-size: @baseFontSize * 1.5; + font-weight: 200; + line-height: @baseLineHeight * 1.5; +} + + +// Emphasis & misc +// ------------------------- + +// Ex: 14px base font * 85% = about 12px +small { font-size: 85%; } + +strong { font-weight: bold; } +em { font-style: italic; } +cite { font-style: normal; } + +// Utility classes +.muted { color: @grayLight; } +a.muted:hover, +a.muted:focus { color: darken(@grayLight, 10%); } + +.text-warning { color: @warningText; } +a.text-warning:hover, +a.text-warning:focus { color: darken(@warningText, 10%); } + +.text-error { color: @errorText; } +a.text-error:hover, +a.text-error:focus { color: darken(@errorText, 10%); } + +.text-info { color: @infoText; } +a.text-info:hover, +a.text-info:focus { color: darken(@infoText, 10%); } + +.text-success { color: @successText; } +a.text-success:hover, +a.text-success:focus { color: darken(@successText, 10%); } + +.text-left { text-align: left; } +.text-right { text-align: right; } +.text-center { text-align: center; } + + +// Headings +// ------------------------- + +h1, h2, h3, h4, h5, h6 { + margin: (@baseLineHeight / 2) 0; + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; + line-height: @baseLineHeight; + color: @headingsColor; + text-rendering: optimizelegibility; // Fix the character spacing for headings + small { + font-weight: normal; + line-height: 1; + color: @grayLight; + } +} + +h1, +h2, +h3 { line-height: @baseLineHeight * 2; } + +h1 { font-size: @baseFontSize * 2.75; } // ~38px +h2 { font-size: @baseFontSize * 2.25; } // ~32px +h3 { font-size: @baseFontSize * 1.75; } // ~24px +h4 { font-size: @baseFontSize * 1.25; } // ~18px +h5 { font-size: @baseFontSize; } +h6 { font-size: @baseFontSize * 0.85; } // ~12px + +h1 small { font-size: @baseFontSize * 1.75; } // ~24px +h2 small { font-size: @baseFontSize * 1.25; } // ~18px +h3 small { font-size: @baseFontSize; } +h4 small { font-size: @baseFontSize; } + + +// Page header +// ------------------------- + +.page-header { + padding-bottom: (@baseLineHeight / 2) - 1; + margin: @baseLineHeight 0 (@baseLineHeight * 1.5); + border-bottom: 1px solid @grayLighter; +} + + + +// Lists +// -------------------------------------------------- + +// Unordered and Ordered lists +ul, ol { + padding: 0; + margin: 0 0 @baseLineHeight / 2 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +li { + line-height: @baseLineHeight; +} + +// Remove default list styles +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +// Single-line list items +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; + > li { + display: inline-block; + .ie7-inline-block(); + padding-left: 5px; + padding-right: 5px; + } +} + +// Description Lists +dl { + margin-bottom: @baseLineHeight; +} +dt, +dd { + line-height: @baseLineHeight; +} +dt { + font-weight: bold; +} +dd { + margin-left: @baseLineHeight / 2; +} +// Horizontal layout (like forms) +.dl-horizontal { + .clearfix(); // Ensure dl clears floats if empty dd elements present + dt { + float: left; + width: @horizontalComponentOffset - 20; + clear: left; + text-align: right; + .text-overflow(); + } + dd { + margin-left: @horizontalComponentOffset; + } +} + +// MISC +// ---- + +// Horizontal rules +hr { + margin: @baseLineHeight 0; + border: 0; + border-top: 1px solid @hrBorder; + border-bottom: 1px solid @white; +} + +// Abbreviations and acronyms +abbr[title], +// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted @grayLight; +} +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +// Blockquotes +blockquote { + padding: 0 0 0 15px; + margin: 0 0 @baseLineHeight; + border-left: 5px solid @grayLighter; + p { + margin-bottom: 0; + font-size: @baseFontSize * 1.25; + font-weight: 300; + line-height: 1.25; + } + small { + display: block; + line-height: @baseLineHeight; + color: @grayLight; + &:before { + content: '\2014 \00A0'; + } + } + + // Float right with text-align: right + &.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid @grayLighter; + border-left: 0; + p, + small { + text-align: right; + } + small { + &:before { + content: ''; + } + &:after { + content: '\00A0 \2014'; + } + } + } +} + +// Quotes +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +// Addresses +address { + display: block; + margin-bottom: @baseLineHeight; + font-style: normal; + line-height: @baseLineHeight; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/utilities.less b/openid-connect-server-webapp/src/main/webapp/less/utilities.less new file mode 100644 index 000000000..314b4ffdb --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/utilities.less @@ -0,0 +1,30 @@ +// +// Utility classes +// -------------------------------------------------- + + +// Quick floats +.pull-right { + float: right; +} +.pull-left { + float: left; +} + +// Toggling content +.hide { + display: none; +} +.show { + display: block; +} + +// Visibility +.invisible { + visibility: hidden; +} + +// For Affix plugin +.affix { + position: fixed; +} diff --git a/openid-connect-server-webapp/src/main/webapp/less/variables.less b/openid-connect-server-webapp/src/main/webapp/less/variables.less new file mode 100644 index 000000000..31c131b1e --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/variables.less @@ -0,0 +1,301 @@ +// +// Variables +// -------------------------------------------------- + + +// Global values +// -------------------------------------------------- + + +// Grays +// ------------------------- +@black: #000; +@grayDarker: #222; +@grayDark: #333; +@gray: #555; +@grayLight: #999; +@grayLighter: #eee; +@white: #fff; + + +// Accent colors +// ------------------------- +@blue: #049cdb; +@blueDark: #0064cd; +@green: #46a546; +@red: #9d261d; +@yellow: #ffc40d; +@orange: #f89406; +@pink: #c3325f; +@purple: #7a43b6; + + +// Scaffolding +// ------------------------- +@bodyBackground: @white; +@textColor: @grayDark; + + +// Links +// ------------------------- +@linkColor: #08c; +@linkColorHover: darken(@linkColor, 15%); + + +// Typography +// ------------------------- +@sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; +@serifFontFamily: Georgia, "Times New Roman", Times, serif; +@monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace; + +@baseFontSize: 14px; +@baseFontFamily: @sansFontFamily; +@baseLineHeight: 20px; +@altFontFamily: @serifFontFamily; + +@headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily +@headingsFontWeight: bold; // instead of browser default, bold +@headingsColor: inherit; // empty to use BS default, @textColor + + +// Component sizing +// ------------------------- +// Based on 14px font-size and 20px line-height + +@fontSizeLarge: @baseFontSize * 1.25; // ~18px +@fontSizeSmall: @baseFontSize * 0.85; // ~12px +@fontSizeMini: @baseFontSize * 0.75; // ~11px + +@paddingLarge: 11px 19px; // 44px +@paddingSmall: 2px 10px; // 26px +@paddingMini: 0 6px; // 22px + +@baseBorderRadius: 4px; +@borderRadiusLarge: 6px; +@borderRadiusSmall: 3px; + + +// Tables +// ------------------------- +@tableBackground: transparent; // overall background-color +@tableBackgroundAccent: #f9f9f9; // for striping +@tableBackgroundHover: #f5f5f5; // for hover +@tableBorder: #ddd; // table and cell border + +// Buttons +// ------------------------- +@btnBackground: @white; +@btnBackgroundHighlight: darken(@white, 10%); +@btnBorder: #ccc; + +@btnPrimaryBackground: @linkColor; +@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); + +@btnInfoBackground: #5bc0de; +@btnInfoBackgroundHighlight: #2f96b4; + +@btnSuccessBackground: #62c462; +@btnSuccessBackgroundHighlight: #51a351; + +@btnWarningBackground: lighten(@orange, 15%); +@btnWarningBackgroundHighlight: @orange; + +@btnDangerBackground: #ee5f5b; +@btnDangerBackgroundHighlight: #bd362f; + +@btnInverseBackground: #444; +@btnInverseBackgroundHighlight: @grayDarker; + + +// Forms +// ------------------------- +@inputBackground: @white; +@inputBorder: #ccc; +@inputBorderRadius: @baseBorderRadius; +@inputDisabledBackground: @grayLighter; +@formActionsBackground: #f5f5f5; +@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border + + +// Dropdowns +// ------------------------- +@dropdownBackground: @white; +@dropdownBorder: rgba(0,0,0,.2); +@dropdownDividerTop: #e5e5e5; +@dropdownDividerBottom: @white; + +@dropdownLinkColor: @grayDark; +@dropdownLinkColorHover: @white; +@dropdownLinkColorActive: @white; + +@dropdownLinkBackgroundActive: @linkColor; +@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; + + + +// COMPONENT VARIABLES +// -------------------------------------------------- + + +// Z-index master list +// ------------------------- +// Used for a bird's eye view of components dependent on the z-axis +// Try to avoid customizing these :) +@zindexDropdown: 1000; +@zindexPopover: 1010; +@zindexTooltip: 1030; +@zindexFixedNavbar: 1030; +@zindexModalBackdrop: 1040; +@zindexModal: 1050; + + +// Sprite icons path +// ------------------------- +@iconSpritePath: "../img/glyphicons-halflings.png"; +@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png"; + + +// Input placeholder text color +// ------------------------- +@placeholderText: @grayLight; + + +// Hr border color +// ------------------------- +@hrBorder: @grayLighter; + + +// Horizontal forms & lists +// ------------------------- +@horizontalComponentOffset: 180px; + + +// Wells +// ------------------------- +@wellBackground: #f5f5f5; + + +// Navbar +// ------------------------- +@navbarCollapseWidth: 979px; +@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; + +@navbarHeight: 40px; +@navbarBackgroundHighlight: #ffffff; +@navbarBackground: darken(@navbarBackgroundHighlight, 5%); +@navbarBorder: darken(@navbarBackground, 12%); + +@navbarText: #777; +@navbarLinkColor: #777; +@navbarLinkColorHover: @grayDark; +@navbarLinkColorActive: @gray; +@navbarLinkBackgroundHover: transparent; +@navbarLinkBackgroundActive: darken(@navbarBackground, 5%); + +@navbarBrandColor: @navbarLinkColor; + +// Inverted navbar +@navbarInverseBackground: #111111; +@navbarInverseBackgroundHighlight: #222222; +@navbarInverseBorder: #252525; + +@navbarInverseText: @grayLight; +@navbarInverseLinkColor: @grayLight; +@navbarInverseLinkColorHover: @white; +@navbarInverseLinkColorActive: @navbarInverseLinkColorHover; +@navbarInverseLinkBackgroundHover: transparent; +@navbarInverseLinkBackgroundActive: @navbarInverseBackground; + +@navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); +@navbarInverseSearchBackgroundFocus: @white; +@navbarInverseSearchBorder: @navbarInverseBackground; +@navbarInverseSearchPlaceholderColor: #ccc; + +@navbarInverseBrandColor: @navbarInverseLinkColor; + + +// Pagination +// ------------------------- +@paginationBackground: #fff; +@paginationBorder: #ddd; +@paginationActiveBackground: #f5f5f5; + + +// Hero unit +// ------------------------- +@heroUnitBackground: @grayLighter; +@heroUnitHeadingColor: inherit; +@heroUnitLeadColor: inherit; + + +// Form states and alerts +// ------------------------- +@warningText: #c09853; +@warningBackground: #fcf8e3; +@warningBorder: darken(spin(@warningBackground, -10), 3%); + +@errorText: #b94a48; +@errorBackground: #f2dede; +@errorBorder: darken(spin(@errorBackground, -10), 3%); + +@successText: #468847; +@successBackground: #dff0d8; +@successBorder: darken(spin(@successBackground, -10), 5%); + +@infoText: #3a87ad; +@infoBackground: #d9edf7; +@infoBorder: darken(spin(@infoBackground, -10), 7%); + + +// Tooltips and popovers +// ------------------------- +@tooltipColor: #fff; +@tooltipBackground: #000; +@tooltipArrowWidth: 5px; +@tooltipArrowColor: @tooltipBackground; + +@popoverBackground: #fff; +@popoverArrowWidth: 10px; +@popoverArrowColor: #fff; +@popoverTitleBackground: darken(@popoverBackground, 3%); + +// Special enhancement for popovers +@popoverArrowOuterWidth: @popoverArrowWidth + 1; +@popoverArrowOuterColor: rgba(0,0,0,.25); + + + +// GRID +// -------------------------------------------------- + + +// Default 940px grid +// ------------------------- +@gridColumns: 12; +@gridColumnWidth: 60px; +@gridGutterWidth: 20px; +@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); + +// 1200px min +@gridColumnWidth1200: 70px; +@gridGutterWidth1200: 30px; +@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); + +// 768px-979px +@gridColumnWidth768: 42px; +@gridGutterWidth768: 20px; +@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); + + +// Fluid grid +// ------------------------- +@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); +@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth); + +// 1200px min +@fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200); +@fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200); + +// 768px-979px +@fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768); +@fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768); diff --git a/openid-connect-server-webapp/src/main/webapp/less/wells.less b/openid-connect-server-webapp/src/main/webapp/less/wells.less new file mode 100644 index 000000000..84a744b1c --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/less/wells.less @@ -0,0 +1,29 @@ +// +// Wells +// -------------------------------------------------- + + +// Base class +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: @wellBackground; + border: 1px solid darken(@wellBackground, 7%); + .border-radius(@baseBorderRadius); + .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); + blockquote { + border-color: #ddd; + border-color: rgba(0,0,0,.15); + } +} + +// Sizes +.well-large { + padding: 24px; + .border-radius(@borderRadiusLarge); +} +.well-small { + padding: 9px; + .border-radius(@borderRadiusSmall); +} diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings-white.png b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings-white.png new file mode 100644 index 000000000..3bf6484a2 Binary files /dev/null and b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings-white.png differ diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings.png b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings.png new file mode 100644 index 000000000..a99699932 Binary files /dev/null and b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/img/glyphicons-halflings.png differ diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.js b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.js new file mode 100644 index 000000000..44109f62d --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.js @@ -0,0 +1,2280 @@ +/* =================================================== + * bootstrap-transition.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#transitions + * =================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#alerts + * ========================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#buttons + * ============================================================ + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#carousel + * ========================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + + , to: function (pos) { + var activeIndex = this.getActiveIndex() + , that = this + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activeIndex == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#collapse + * ============================================================= + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#dropdowns + * ============================================================ + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('
  • ' + , minLength: 1 + } + + $.fn.typeahead.Constructor = Typeahead + + + /* TYPEAHEAD NO CONFLICT + * =================== */ + + $.fn.typeahead.noConflict = function () { + $.fn.typeahead = old + return this + } + + + /* TYPEAHEAD DATA-API + * ================== */ + + $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { + var $this = $(this) + if ($this.data('typeahead')) return + $this.typeahead($this.data()) + }) + +}(window.jQuery); +/* ========================================================== + * bootstrap-affix.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#affix + * ========================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* AFFIX CLASS DEFINITION + * ====================== */ + + var Affix = function (element, options) { + this.options = $.extend({}, $.fn.affix.defaults, options) + this.$window = $(window) + .on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this)) + this.$element = $(element) + this.checkPosition() + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + , scrollTop = this.$window.scrollTop() + , position = this.$element.offset() + , offset = this.options.offset + , offsetBottom = offset.bottom + , offsetTop = offset.top + , reset = 'affix affix-top affix-bottom' + , affix + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top() + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() + + affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? + false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? + 'bottom' : offsetTop != null && scrollTop <= offsetTop ? + 'top' : false + + if (this.affixed === affix) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? position.top - scrollTop : null + + this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : '')) + } + + + /* AFFIX PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.affix + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('affix') + , options = typeof option == 'object' && option + if (!data) $this.data('affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + $.fn.affix.defaults = { + offset: 0 + } + + + /* AFFIX NO CONFLICT + * ================= */ + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + /* AFFIX DATA-API + * ============== */ + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + , data = $spy.data() + + data.offset = data.offset || {} + + data.offsetBottom && (data.offset.bottom = data.offsetBottom) + data.offsetTop && (data.offset.top = data.offsetTop) + + $spy.affix(data) + }) + }) + + +}(window.jQuery); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.min.js b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.min.js new file mode 100644 index 000000000..848258d38 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/resources/bootstrap2/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! +* Bootstrap.js by @fat & @mdo +* Copyright 2013 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('