You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by an...@apache.org on 2015/10/30 10:34:01 UTC

[1/4] syncope git commit: SYNCOPE-701 first working implementation

Repository: syncope
Updated Branches:
  refs/heads/master 764fa2eca -> 714557e64


http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html b/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
new file mode 100644
index 0000000..9361cdf
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<div ng-cloak class="container">
+  <div class="login-container" ng-controller="UserController" ng-init="initUser();" style="box-sizing: border-box; ">
+
+    <div id="form-container" class="col-md-6 col-md-offset-3">
+
+
+      <div>
+        <div class="page-header" style="text-align: left; font-weight: 700;">
+          <span ng-show="createMode">New User</span>
+          <span ng-show="!createMode">User {{user.username}}</span>
+        </div>
+        <div class="breadcrumb-header text-center">
+
+          <!-- the links to our nested states using relative paths -->
+          <!-- add the active class if the state matches our ui-sref -->
+          <!--<div id="status-buttons" class="text-center">-->
+          <div class="row">
+            <div growl reference="2" inline="true"></div>
+            <div id="status-buttons" class="btn-group btn-breadcrumb">
+              <a href="#/self" class="btn btn-default"><i class="glyphicon glyphicon-home"></i></a>
+              <!--add class breadcrumb-disabled-link to buttons to prevent click-->
+              <a ui-sref-active="active" ui-sref=".credentials" class="btn btn-default">Credentials</a>
+              <a ui-sref-active="active" ui-sref=".plainSchemas" class="btn btn-default">Plain Schemas</a>
+              <a ui-sref-active="active" ui-sref=".derivedSchemas" class="btn btn-default">Derived Schemas</a>
+              <a ui-sref-active="active" ui-sref=".virtualSchemas" class="btn btn-default">Virtual Schemas</a>
+              <a ui-sref-active="active" ui-sref=".groups" class="btn btn-default">Groups</a>
+              <a ui-sref-active="active" ui-sref=".resources" class="btn btn-default">Resources</a>
+            </div>
+          </div>
+        </div>
+        <form class="signup-form" name="userForm" ng-submit="saveUser(user)" novalidate>
+
+          <div id="form-views" ui-view>
+
+            <!--            <div class="form-group row">
+                          <div class="col-xs-6 col-xs-offset-3">
+                            <a id="next" ui-sref="create.credentials" class="btn btn-block btn-signin">
+                              Start <span class="glyphicon glyphicon-circle-arrow-right"></span>
+                            </a> 
+                            <a id="cancel" href="#/self" class="btn btn-link">Cancel</a>
+                          </div>
+                        </div>-->
+
+          </div>
+          <!--            <div class="form-actions">
+                        <button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary" ng-click="saveUser()">Register</button>
+                        <img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
+                        <a href="#/self" class="btn btn-link">Cancel</a>
+                      </div>-->
+        </form>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/generic-error.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/generic-error.html b/client/enduser/src/main/resources/META-INF/resources/app/views/generic-error.html
new file mode 100644
index 0000000..2ca6c58
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/generic-error.html
@@ -0,0 +1,24 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<html>
+  <body>
+    <div>PAGE NOT FOUND</div>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/home.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/home.html b/client/enduser/src/main/resources/META-INF/resources/app/views/home.html
new file mode 100644
index 0000000..ca365ff
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/home.html
@@ -0,0 +1,34 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<html>
+  <body>
+    <div>TITLE GET FROM CONTROLLER:</div>
+    <p>{{title}}</p>
+    <p>{{subtitle}}</p>
+    <p>{{name}}</p>
+    
+    <button type="button" ng-click="">Password Reset</button>
+    <button type="button" ng-click="">Self Registration</button>
+    <button type="button" ng-click="">Self Update</button>
+    <button type="button" ng-click="sampleAPI()">Sample</button>
+    <button type="button" ng-click="errorAPI()">Error</button>
+    
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/navigationButtons.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/navigationButtons.html b/client/enduser/src/main/resources/META-INF/resources/app/views/navigationButtons.html
new file mode 100644
index 0000000..793334d
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/navigationButtons.html
@@ -0,0 +1,8 @@
+<div class="col-xs-6 col-xs-offset-3">
+  <a ng-show="next !== 'none'" id="next" ui-sref="{{next}}" class="btn btn-default">
+    Next <span class="glyphicon glyphicon-circle-arrow-right"></span>
+  </a>
+  <a ng-show="previous !== 'none'" id="previous" ui-sref="{{previous}}" class="btn btn-default">
+    <span class="glyphicon glyphicon-circle-arrow-left"></span> Previous
+  </a>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/self.html b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
new file mode 100644
index 0000000..0139697
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
@@ -0,0 +1,131 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+    <meta charset="UTF-8"/>
+    <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'/>
+
+    <title>Apache Syncope Enduser - Login</title>
+  </head>
+
+  <body>
+
+    <div ng-cloak class="container">
+
+      <div id="login-container" ng-controller="LoginController"  style="box-sizing: border-box; ">
+
+        <!--        <div id="logo">
+                  <a href="/">
+                    <img class="login-logo" src="img/logo-green.png" />
+                  </a>
+                </div>-->
+        <div id="login">
+          <div class="logout">
+            <a href="javascript:void(0);" class="btn btn-danger btn-signin" ng-click="logout()" ng-show="isLogged()" title="Logout">
+              <i class="glyphicon glyphicon-off"></i>
+            </a>
+          </div>
+          <div>
+            <div id="language" class="form-group" ng-controller="LanguageController" ng-init="init()">
+              <div id="languageContainer" class="col-xs-2">
+
+                <select class="form-control" ng-options="language.name for language in languages.availableLanguages track by language.id"
+                        ng-model="languages.selectedLanguage" ></select>
+
+              </div>
+            </div>
+
+            <h3>Welcome to Apache Syncope Enduser</h3>
+            <h5 ng-show="!isLogged()">please login to self update</h5>
+
+            <div id="login-form" class="form">
+              <div growl reference="1" inline="true"></div>
+            </div>
+            
+            <form id="login-form" class="form" novalidate ng-show="!isLogged()" >
+
+              <div class="form-group">
+                <input autofocus="autofocus" type="text" class="form-control" id="login-username" placeholder="Username"
+                       ng-required ng-model="credentials.username" placeholder="username">
+              </div>
+
+              <div class="form-group">
+                <input type="password" class="form-control" id="login-password" placeholder="Password" 
+                       ng-required ng-model="credentials.password" placeholder="password">
+              </div>
+
+              <div class="form-group">
+
+                <button type="submit" id="login-btn" class="btn btn-default btn-signin login-btn" ng-click="login(credentials)">Login</button>
+                <a href="javascript:void(0);" class="btn btn-link" ng-click="selfCreate()">Self Registration</a>
+                <a href="javascript:void(0);" class="btn btn-link" ng-click="passwordReset()">Password Reset</a>
+              </div>
+            </form>
+
+          </div>
+
+        </div>
+
+      </div>
+
+    </div> <!-- /#login -->
+
+    <!--      <div id="initialLoaderDiv">
+            <img src="img/busy.gif" class="ajax-loader"/>
+          </div>-->
+    </div> <!-- /#login-container -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    <!--    <div class="container" ng-cloak ng-controller="LoginController">
+          <div class="card card-container">
+            <img class="login-logo" src="img/logo-green.png" />
+    
+            <div growl></div>
+    
+            <form class="form-signin"  novalidate ng-show="!isLogged()">
+              <input type="text" id="username" class="form-control" ng-required autofocus="autofocus" ng-model="credentials.username" />
+              <input type="password" id="password" class="form-control" required="required" ng-model="credentials.password" />
+    
+              <select id="language" style="width: 100%" 
+                      ng-options="language.name for language in languages.availableLanguages track by language.id" 
+                      ng-model="languages.selectedLanguage"></select>
+    
+              <button type="submit" class="btn btn-lg btn-primary btn-block btn-signin" ng-click="login(credentials)">Login</button>
+            </form>
+    
+            
+    
+          </div>
+        </div>-->
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
new file mode 100644
index 0000000..cfd1ba6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<div id="attribute" class="form-group">
+  <label for="user.username">Username</label>
+  <input name="username" type="text" class="form-control" ng-model="user.username" required placeholder="username" >
+  <p ng-show="(userForm.username.$error.required && !userForm.username.$pristine)" class="text-validation-error">Username is required</p>
+</div>
+
+<div id="attribute" class="form-group">
+  <label for="user.password">Password</label>
+  <input type="password" class="form-control" name="password" ng-model="user.password" equals="{{confirmPassword.value}}"
+         placeholder="password">
+</div>
+
+<div id="attribute" class="form-group">
+  <label for="confirmPassword">Confirm Password</label>
+  <input name="confirmPassword" type="password" class="form-control" equals="{{user.password}}" ng-model="confirmPassword.value"
+         placeholder="confirm password">
+  <p ng-show="userForm.confirmPassword.$error.equals" class="text-validation-error">Password and confirm password must be equal</p>
+</div>
+
+<div id="attribute" class="form-group">
+  <label for="securityQuestion">Security Question</label>
+  <select name="securityQuestion" class="form-control"
+          ng-model="user.securityQuestion"
+          ng-options="securityQuestion.key as securityQuestion.content for securityQuestion in availableSecurityQuestions">
+    <option value="">Select security question</option>
+  </select>
+</div>
+
+<div id="attribute" class="form-group">
+  <label for="securityAnswer">Security Answer</label>
+  <input ng-disabled="user.securityQuestion === initialSecurityQuestion" name="securityAnswer" type="text" class="form-control" ng-model="user.securityAnswer"
+         placeholder="security answer">
+</div>
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="create.plainSchemas" previous="none"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="update.plainSchemas" previous="none"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
new file mode 100644
index 0000000..a92b9c2
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
@@ -0,0 +1,37 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<div id="attribute-derived" class="form-group" >
+  <div>
+    <dynamic-derived-attributes user="user" form="dynamicForm"></dynamic-derived-attributes>
+  </div>
+  <!--    <div style="color:#dd301b" ng-if="attribute.validated == false" class="row-fluid">
+        <div class="col-md-5"></div>
+        <div class="col-md-7">{{attribute.validationMessage| translate }}</div>
+      </div>-->
+  <!--</div>-->
+</div>
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="create.virtualSchemas" previous="create.plainSchemas"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="update.virtualSchemas" previous="update.plainSchemas"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
new file mode 100644
index 0000000..58475bb
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<div class="form-group row upper-select">
+  <label>Realm</label>
+  <select class="form-control"
+          ng-disabled="true"
+          ng-model="user.realm"
+          ng-required="true">
+    <option ng-repeat="realm in availableRealms" value="{{realm}}">{{realm}}</option>
+  </select>
+</div>
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="create.resources" previous="create.virtualSchemas"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="update.resources" previous="update.virtualSchemas"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
new file mode 100644
index 0000000..2639197
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
@@ -0,0 +1,37 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<div>
+  <dynamic-plain-attributes form="dynamicForm" user="user"></dynamic-plain-attributes>
+</div>
+
+<!--    <div style="color:#dd301b" ng-if="attribute.validated == false" class="row-fluid">
+      <div class="col-md-5"></div>
+      <div class="col-md-7">{{attribute.validationMessage| translate }}</div>
+    </div>-->
+<!--</div>-->
+<!--</div>-->
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="create.derivedSchemas" previous="create.credentials"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="update.derivedSchemas" previous="update.credentials"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
new file mode 100644
index 0000000..91a99f6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="none" previous="create.groups"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="none" previous="update.groups"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+    <button id="save" type="submit" class="btn btn-success">Save</button>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
new file mode 100644
index 0000000..1d77c80
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
@@ -0,0 +1,37 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<div id="attribute-virtual" class="form-group">
+  <div>
+    <dynamic-virtual-attributes form="dynamicForm" user="user"></dynamic-virtual-attributes>
+  </div>
+  <!--    <div style="color:#dd301b" ng-if="attribute.validated == false" class="row-fluid">
+        <div class="col-md-5"></div>
+        <div class="col-md-7">{{attribute.validationMessage| translate }}</div>
+      </div>-->
+  <!--</div>-->
+</div>
+
+<div class="form-group row">
+  <navigation-buttons ng-show="createMode" next="create.groups" previous="create.derivedSchemas"></navigation-buttons>
+  <navigation-buttons ng-show="!createMode" next="update.groups" previous="update.derivedSchemas"></navigation-buttons>
+  <div class="col-xs-6 col-xs-offset-3">
+    <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/web-fragment.xml
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/web-fragment.xml b/client/enduser/src/main/resources/META-INF/web-fragment.xml
new file mode 100644
index 0000000..b949d4c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/web-fragment.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<web-fragment xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
+                                  http://xmlns.jcp.org/xml/ns/javaee/web-fragment_3_1.xsd"
+              id="${pom.artifactId}" version="3.1">
+  
+  <!--causes problem if deployed with other fragments-->
+  <display-name>Apache Syncope ${syncope.version} Enduser</display-name>
+
+<!--  <context-param>
+    <param-name>configuration</param-name>
+    <param-value>deployment</param-value>
+  </context-param>
+    
+  <filter>
+    <filter-name>SyncopeEnduser</filter-name>
+    <filter-class>org.apache.wicket.protocol.ws.javax.JavaxWebSocketFilter</filter-class>
+    <init-param>
+      <param-name>filterMappingUrlPattern</param-name>
+      <param-value>/*</param-value>
+    </init-param>
+    <init-param>
+      <param-name>applicationClassName</param-name>
+      <param-value>org.apache.syncope.client.enduser.SyncopeEnduserApplication</param-value>
+    </init-param>
+  </filter>-->
+  
+    <filter>
+    <filter-name>SyncopeEnduser</filter-name>
+    <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+    <init-param>
+      <param-name>applicationClassName</param-name>
+      <param-value>org.apache.syncope.client.enduser.SyncopeEnduserApplication</param-value>
+    </init-param>
+    <init-param>
+      <param-name>filterMappingUrlPattern</param-name>
+      <param-value>/*</param-value>
+    </init-param>
+  </filter>
+  
+  <filter-mapping>
+    <filter-name>SyncopeEnduser</filter-name>
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>INCLUDE</dispatcher>
+  </filter-mapping>
+  
+  <!--SESSION TIMEOUT (MINUTES)-->
+  <session-config>
+    <session-timeout>30</session-timeout>
+  </session-config>
+
+</web-fragment>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/enduser.properties
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/enduser.properties b/client/enduser/src/main/resources/enduser.properties
new file mode 100644
index 0000000..4dd1cbe
--- /dev/null
+++ b/client/enduser/src/main/resources/enduser.properties
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+enduser.directory=${conf.directory}
+scheme=http
+host=localhost
+port=8080
+rootPath=/syncope/rest/
+
+anonymousUser=${anonymousUser}
+anonymousKey=${anonymousKey}
+
+storePassword=true
+
+version=${syncope.version}
+license=${licenseUrl}
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/HomePage.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/HomePage.html b/client/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/HomePage.html
new file mode 100644
index 0000000..55d71a4
--- /dev/null
+++ b/client/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/HomePage.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html>
+  
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java b/client/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
new file mode 100644
index 0000000..4a77739
--- /dev/null
+++ b/client/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser;
+
+import org.apache.syncope.client.enduser.pages.HomePage;
+import org.apache.wicket.Session;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.protocol.http.mock.MockHttpServletResponse;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.util.tester.WicketTester;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SyncopeEnduserApplicationTest {
+
+    private WicketTester tester;
+
+    static class SyncopeEnduserMockSession extends WebSession {
+
+        private static final long serialVersionUID = -2500230416352618497L;
+
+        SyncopeEnduserMockSession(Request request) {
+            super(request);
+        }
+    }
+
+    @Before
+    public void setUp() {
+        tester = new WicketTester(new SyncopeEnduserApplication() {
+
+            private static final long serialVersionUID = 1445165406200746511L;
+
+            @Override
+            public Session newSession(Request request, Response response) {
+                return new SyncopeEnduserMockSession(request);
+            }
+
+        });
+    }
+
+    @Test
+    public void testRedirectToIndex() {
+        tester.setFollowRedirects(false);
+        tester.startPage(HomePage.class);
+        tester.assertNoErrorMessage();
+        MockHttpServletResponse response = tester.getLastResponse();
+        Assert.assertThat(response.getRedirectLocation(), CoreMatchers.equalTo("app/"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index 68bd1e5..0cefabb 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -60,6 +60,7 @@ under the License.
     <module>lib</module>
     <module>console</module>
     <module>cli</module>
+    <module>enduser</module>
   </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
index 6587d1d..f0c2d15 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/Entitlement.java
@@ -46,22 +46,14 @@ public final class Entitlement {
 
     public static final String REALM_DELETE = "REALM_DELETE";
 
-    public static final String ANYTYPECLASS_LIST = "ANYTYPECLASS_LIST";
-
     public static final String ANYTYPECLASS_CREATE = "ANYTYPECLASS_CREATE";
 
-    public static final String ANYTYPECLASS_READ = "ANYTYPECLASS_READ";
-
     public static final String ANYTYPECLASS_UPDATE = "ANYTYPECLASS_UPDATE";
 
     public static final String ANYTYPECLASS_DELETE = "ANYTYPECLASS_DELETE";
 
-    public static final String ANYTYPE_LIST = "ANYTYPE_LIST";
-
     public static final String ANYTYPE_CREATE = "ANYTYPE_CREATE";
 
-    public static final String ANYTYPE_READ = "ANYTYPE_READ";
-
     public static final String ANYTYPE_UPDATE = "ANYTYPE_UPDATE";
 
     public static final String ANYTYPE_DELETE = "ANYTYPE_DELETE";
@@ -90,8 +82,6 @@ public final class Entitlement {
 
     public static final String SCHEMA_CREATE = "SCHEMA_CREATE";
 
-    public static final String SCHEMA_READ = "SCHEMA_READ";
-
     public static final String SCHEMA_UPDATE = "SCHEMA_UPDATE";
 
     public static final String SCHEMA_DELETE = "SCHEMA_DELETE";

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
index 1743370..7ccd2bf 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
@@ -44,7 +44,7 @@ public class AnyTypeClassLogic extends AbstractTransactionalLogic<AnyTypeClassTO
     @Autowired
     private AnyTypeClassDAO anyTypeClassDAO;
 
-    @PreAuthorize("hasRole('" + Entitlement.ANYTYPECLASS_READ + "')")
+    @PreAuthorize("isAuthenticated()")
     public AnyTypeClassTO read(final String key) {
         AnyTypeClass anyType = anyTypeClassDAO.find(key);
         if (anyType == null) {
@@ -56,7 +56,7 @@ public class AnyTypeClassLogic extends AbstractTransactionalLogic<AnyTypeClassTO
         return binder.getAnyTypeClassTO(anyType);
     }
 
-    @PreAuthorize("hasRole('" + Entitlement.ANYTYPECLASS_LIST + "')")
+    @PreAuthorize("isAuthenticated()")
     public List<AnyTypeClassTO> list() {
         return CollectionUtils.collect(anyTypeClassDAO.findAll(), new Transformer<AnyTypeClass, AnyTypeClassTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
index 1ff60c7..6bd0fd5 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
@@ -46,7 +46,7 @@ public class AnyTypeLogic extends AbstractTransactionalLogic<AnyTypeTO> {
     @Autowired
     private AnyTypeDAO anyTypeDAO;
 
-    @PreAuthorize("hasRole('" + Entitlement.ANYTYPE_READ + "')")
+    @PreAuthorize("isAuthenticated()")
     public AnyTypeTO read(final String key) {
         AnyType anyType = anyTypeDAO.find(key);
         if (anyType == null) {
@@ -58,7 +58,7 @@ public class AnyTypeLogic extends AbstractTransactionalLogic<AnyTypeTO> {
         return binder.getAnyTypeTO(anyType);
     }
 
-    @PreAuthorize("hasRole('" + Entitlement.ANYTYPE_LIST + "')")
+    @PreAuthorize("isAuthenticated()")
     public List<AnyTypeTO> list() {
         return CollectionUtils.collect(anyTypeDAO.findAll(), new Transformer<AnyType, AnyTypeTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/core/logic/src/main/java/org/apache/syncope/core/logic/SchemaLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/SchemaLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/SchemaLogic.java
index 3da4a76..cbd5f64 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/SchemaLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/SchemaLogic.java
@@ -180,7 +180,7 @@ public class SchemaLogic extends AbstractTransactionalLogic<AbstractSchemaTO> {
         return result;
     }
 
-    @PreAuthorize("hasRole('" + Entitlement.SCHEMA_READ + "')")
+    @PreAuthorize("isAuthenticated()")
     @SuppressWarnings("unchecked")
     public <T extends AbstractSchemaTO> T read(final SchemaType schemaType, final String schemaName) {
         T read;

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java
index e5cf78b..811b429 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java
@@ -118,15 +118,6 @@ public class AuthenticationITCase extends AbstractITCase {
 
     @Test
     public void testUserSchemaAuthorization() {
-        // 0. create a role that can only read schemas
-        RoleTO roleTO = new RoleTO();
-        roleTO.setName("authRole" + getUUIDString());
-        roleTO.getEntitlements().add(Entitlement.SCHEMA_READ);
-        roleTO.getRealms().add("/odd");
-
-        roleTO = createRole(roleTO);
-        assertNotNull(roleTO);
-
         String schemaName = "authTestSchema" + getUUIDString();
 
         // 1. create a schema (as admin)
@@ -140,8 +131,6 @@ public class AuthenticationITCase extends AbstractITCase {
 
         // 2. create an user with the role created above (as admin)
         UserTO userTO = UserITCase.getUniqueSampleTO("auth@test.org");
-        userTO.getRoles().add(roleTO.getKey());
-
         userTO = createUser(userTO).getAny();
         assertNotNull(userTO);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/pom.xml b/fit/enduser-reference/pom.xml
new file mode 100644
index 0000000..aee8f79
--- /dev/null
+++ b/fit/enduser-reference/pom.xml
@@ -0,0 +1,413 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope</groupId>
+    <artifactId>syncope-fit</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope FIT Enduser Reference</name>
+  <description>Apache Syncope FIT Enduser Reference</description>
+  <groupId>org.apache.syncope.fit</groupId>
+  <artifactId>syncope-fit-enduser-reference</artifactId>
+  <packaging>war</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.syncope.client</groupId>
+      <artifactId>syncope-client-enduser</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency> 
+      <groupId>javax.servlet</groupId> 
+      <artifactId>javax.servlet-api</artifactId> 
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet.jsp</groupId>
+      <artifactId>javax.servlet.jsp-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>jstl</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency><!--
+-->    
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency><!--
+-->    
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency><!--
+-->    
+    <dependency>
+      <groupId>com.lmax</groupId>
+      <artifactId>disruptor</artifactId>
+    </dependency><!--
+-->    
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+      <scope>provided</scope>
+    </dependency><!--
+-->    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+    </dependency>
+    
+    <!--   TEST -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.fit</groupId>
+      <artifactId>syncope-fit-build-tools</artifactId>
+      <version>${project.version}</version>
+      <type>war</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>net.tirasa.connid.bundles.soap</groupId>
+      <artifactId>wssample</artifactId>
+      <type>war</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.h2database</groupId>
+      <artifactId>h2</artifactId>
+      <scope>test</scope>
+    </dependency><!--
+    
+     SELENIUM INTEGRATION TEST 
+    <dependency>
+      <groupId>org.seleniumhq.selenium</groupId>
+      <artifactId>selenium-java</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.seleniumhq.selenium</groupId>
+      <artifactId>selenium-api</artifactId>
+      <scope>test</scope>
+    </dependency>-->
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-war-plugin</artifactId>
+        <inherited>true</inherited>
+        <configuration>
+          <failOnMissingWebXml>false</failOnMissingWebXml>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.cargo</groupId>
+        <artifactId>cargo-maven2-plugin</artifactId>
+        <inherited>true</inherited>
+        <configuration>
+          <container>
+            <dependencies>
+              <dependency>
+                <groupId>com.h2database</groupId>
+                <artifactId>h2</artifactId>
+              </dependency>
+            </dependencies>
+          </container>
+          <configuration>
+            <type>standalone</type>
+            <properties>
+              <cargo.servlet.port>${cargo.servlet.port}</cargo.servlet.port>
+              <cargo.tomcat.ajp.port>${cargo.tomcat.ajp.port}</cargo.tomcat.ajp.port>
+              <cargo.rmi.port>${cargo.rmi.port}</cargo.rmi.port>
+
+              <cargo.jvmargs>-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m</cargo.jvmargs>
+            </properties>
+            <configfiles>
+              <configfile>
+                <file>${project.build.directory}/classes/context.xml</file>
+                <todir>conf/</todir>
+                <tofile>context.xml</tofile>
+              </configfile>
+            </configfiles>
+          </configuration>
+          <deployables>
+            <deployable>
+              <groupId>net.tirasa.connid.bundles.soap</groupId>
+              <artifactId>wssample</artifactId>
+              <type>war</type>
+              <properties>
+                <context>wssample</context>
+              </properties>
+            </deployable>
+            <deployable>
+              <groupId>org.apache.syncope.fit</groupId>
+              <artifactId>syncope-fit-build-tools</artifactId>
+              <type>war</type>
+              <properties>
+                <context>syncope-fit-build-tools</context>
+              </properties>
+            </deployable>
+            <deployable>
+              <location>${basedir}/../core-reference/target/syncope-fit-core-reference-${project.version}</location>
+              <pingURL>http://localhost:${cargo.servlet.port}/syncope/cacheStats.jsp</pingURL>
+              <pingTimeout>60000</pingTimeout>
+              <properties>
+                <context>syncope</context>
+              </properties>
+            </deployable>
+            <deployable>
+              <location>${project.build.directory}/${project.build.finalName}</location>
+              <properties>
+                <context>syncope-enduser</context>
+              </properties>
+            </deployable>
+          </deployables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <resourceIncludes>src/main/resources/**/*.properties</resourceIncludes>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>ianal-maven-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+    
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+  </build>
+  
+  <profiles>
+    <profile>
+      <id>debug</id>
+
+      <properties>
+        <skipTests>true</skipTests>
+      </properties>
+
+      <build>
+        <defaultGoal>clean verify cargo:run</defaultGoal>
+
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-maven2-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <configuration>
+                <properties>
+                  <cargo.jvmargs>-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
+                    -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m</cargo.jvmargs>
+                </properties>
+              </configuration>
+            </configuration>
+            <executions>
+              <execution>
+                <id>start-container</id>
+                <phase>none</phase>
+              </execution>
+              <execution>
+                <id>stop-container</id>
+                <phase>none</phase>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    
+    <profile>
+      <id>skipTests</id>
+
+      <dependencies>
+        <dependency>
+          <groupId>com.h2database</groupId>
+          <artifactId>h2</artifactId>
+        </dependency>
+      </dependencies>
+      
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-maven2-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <deployables>
+                <deployable>
+                  <location>${project.build.directory}/${project.build.finalName}.war</location>
+                </deployable>
+              </deployables>
+            </configuration>
+            <executions>
+              <execution>
+                <id>install-container</id>
+                <phase>package</phase>
+                <goals>
+                  <goal>install</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>start-container</id>
+                <phase>none</phase>
+              </execution>
+              <execution>
+                <id>stop-container</id>
+                <phase>none</phase>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    
+    <profile>
+      <id>jrebel</id>
+      
+      <properties>
+        <javaagent>-javaagent:${env.REBEL_HOME}/jrebel.jar</javaagent>
+      </properties>
+      
+      <build>
+        <defaultGoal>clean verify cargo:run</defaultGoal>
+
+        <plugins>
+          <plugin>
+            <groupId>org.zeroturnaround</groupId>
+            <artifactId>jrebel-maven-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <classpath>
+                <fallback>default</fallback>
+                <resources>
+                  <resource/>
+                  <resource>
+                    <directory>${basedir}/../../client/enduser/target/classes</directory>
+                  </resource>
+                </resources>
+              </classpath>
+              
+              <web>
+                <resources>
+                  <resource/>
+                  <resource>
+                    <target>/</target>
+                    <directory>${basedir}/../../client/enduser/target/classes/META-INF/resources/</directory>
+                  </resource>
+                </resources>
+              </web>
+    
+              <alwaysGenerate>true</alwaysGenerate>
+            </configuration>
+            <executions>
+              <execution>
+                <id>generate-rebel-xml</id>
+                <phase>process-resources</phase>
+                <goals>
+                  <goal>generate</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-maven2-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <configuration>
+                <properties>
+                  <cargo.jvmargs>-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
+                    -noverify ${javaagent} -Drebel.spring_plugin=true 
+                    -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m</cargo.jvmargs>
+                </properties>
+              </configuration>
+            </configuration>
+            <executions>
+              <execution>
+                <id>start-container</id>
+                <phase>none</phase>
+              </execution>
+              <execution>
+                <id>stop-container</id>
+                <phase>none</phase>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    
+    <profile>
+      <id>apache-release</id>
+
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-deploy-plugin</artifactId>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+  </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/resources/context.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/resources/context.xml b/fit/enduser-reference/src/main/resources/context.xml
new file mode 100644
index 0000000..471d561
--- /dev/null
+++ b/fit/enduser-reference/src/main/resources/context.xml
@@ -0,0 +1,23 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<Context>
+  <!-- Disable session persistence across Tomcat restarts -->
+  <Manager pathname=""/>
+</Context>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/resources/enduser.properties
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/resources/enduser.properties b/fit/enduser-reference/src/main/resources/enduser.properties
new file mode 100644
index 0000000..96b0dea
--- /dev/null
+++ b/fit/enduser-reference/src/main/resources/enduser.properties
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+enduser.directory=${conf.directory}
+scheme=http
+host=localhost
+port=9080
+rootPath=/syncope/rest/
+
+anonymousUser=${anonymousUser}
+anonymousKey=${anonymousKey}
+
+storePassword=true
+
+version=${syncope.version}
+license=${licenseUrl}
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/resources/log4j2.xml b/fit/enduser-reference/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..ced0e34
--- /dev/null
+++ b/fit/enduser-reference/src/main/resources/log4j2.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<configuration status="WARN">
+
+  <appenders>
+
+    <RollingRandomAccessFile name="main" fileName="${log.directory}/enduser.log"
+                             filePattern="${log.directory}/enduser-%d{yyyy-MM-dd}.log.gz"
+                             immediateFlush="false" append="true">
+      <PatternLayout>
+        <pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
+      </PatternLayout>
+      <Policies>
+        <TimeBasedTriggeringPolicy/>
+        <SizeBasedTriggeringPolicy size="250 MB"/>
+      </Policies>
+    </RollingRandomAccessFile>
+    
+  </appenders>
+
+  <loggers>
+
+    <asyncLogger name="org.apache.syncope.client.lib" additivity="false" level="OFF">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+
+    <asyncLogger name="org.apache.syncope.client.enduser" additivity="false" level="DEBUG">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+
+    <asyncLogger name="org.apache.wicket" additivity="false" level="DEBUG">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+
+    <root level="DEBUG">
+      <appender-ref ref="main"/>
+    </root>
+  
+  </loggers>
+  
+</configuration>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/webapp/WEB-INF/glassfish-web.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/glassfish-web.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/glassfish-web.xml
new file mode 100644
index 0000000..6400bc2
--- /dev/null
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/glassfish-web.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+
+-->
+<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD 
+GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
+<glassfish-web-app error-url="">
+  <class-loader delegate="false"/>
+</glassfish-web-app>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..f38ebfc
--- /dev/null
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
+  <deployment>
+    <exclude-subsystems>
+      <subsystem name="webservices"/>
+      <subsystem name="jaxrs"/>
+    </exclude-subsystems>
+    <dependencies>
+      <module name="org.apache.xalan"/>
+    </dependencies>
+    <exclusions>
+      <module name="javax.ws.rs.api"/>
+      <module name="org.apache.cxf"/>
+      <module name="org.apache.cxf.impl"/>
+      <module name="org.slf4j"/>
+      <module name="org.slf4j.impl"/>
+    </exclusions>
+  </deployment>
+</jboss-deployment-structure>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/enduser-reference/src/main/webapp/WEB-INF/weblogic.xml
----------------------------------------------------------------------
diff --git a/fit/enduser-reference/src/main/webapp/WEB-INF/weblogic.xml b/fit/enduser-reference/src/main/webapp/WEB-INF/weblogic.xml
new file mode 100644
index 0000000..6e6bd30
--- /dev/null
+++ b/fit/enduser-reference/src/main/webapp/WEB-INF/weblogic.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" 
+                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+                  xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
+                                      http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
+
+  <context-root>syncope-console</context-root>
+  
+  <container-descriptor>    
+    <prefer-application-packages>
+      <package-name>org.apache.commons.*</package-name>
+      <package-name>org.slf4j.*</package-name>
+      <package-name>com.fasterxml.jackson.*</package-name>
+    </prefer-application-packages>
+  </container-descriptor>
+
+</weblogic-web-app>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/fit/pom.xml
----------------------------------------------------------------------
diff --git a/fit/pom.xml b/fit/pom.xml
index 203e414..072e37a 100644
--- a/fit/pom.xml
+++ b/fit/pom.xml
@@ -60,6 +60,7 @@ under the License.
     <module>build-tools</module>
     <module>core-reference</module>
     <module>console-reference</module>
+    <module>enduser-reference</module>
   </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index bfdfd51..a5ee74a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -388,7 +388,20 @@ under the License.
     
     <wicket.version>7.1.0</wicket.version>
     <wicket-jqueryui.version>7.1.0</wicket-jqueryui.version>
-
+    
+    <angular.version>1.4.7</angular.version>
+    <angular-route.version>1.4.7</angular-route.version>
+    <angular-resource.version>1.4.7</angular-resource.version>
+    <angular-cookies.version>1.4.7</angular-cookies.version>
+    <angular-animate.version>1.4.7</angular-animate.version>
+    <angular-ui-router.version>0.2.15</angular-ui-router.version>
+    <angular-ui-bootstrap.version>0.14.0</angular-ui-bootstrap.version>
+    <angular-ui-select.version>0.13.1</angular-ui-select.version>
+    <angular-sanitize.version>1.4.7</angular-sanitize.version>
+    <angular-growl-2.version>0.7.3</angular-growl-2.version>
+    <select2.version>3.4.8</select2.version>
+    <FileSaver.version>0.0.2</FileSaver.version>
+    
     <izpack.version>5.0.5</izpack.version>
     <httpclient.version>4.3.6</httpclient.version>
     <maven-invoker.version>2.1.1</maven-invoker.version>
@@ -999,6 +1012,79 @@ under the License.
         <artifactId>jquery-cookie</artifactId>
         <version>${jquery-cookie.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular</artifactId>
+        <version>${angular.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular-route</artifactId>
+        <version>${angular-route.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular-resource</artifactId>
+        <version>${angular-resource.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular-cookies</artifactId>
+        <version>${angular-cookies.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars</groupId>
+        <artifactId>angular-ui-router</artifactId>
+        <version>${angular-ui-router.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular-animate</artifactId>
+        <version>${angular-animate.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars</groupId>
+        <artifactId>angular-ui-bootstrap</artifactId>
+        <version>${angular-ui-bootstrap.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars</groupId>
+        <artifactId>angular-ui-select</artifactId>
+        <version>${angular-ui-select.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>angular-sanitize</artifactId>
+        <version>${angular-sanitize.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars</groupId>
+        <artifactId>angular-growl-2</artifactId>
+        <version>${angular-growl-2.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>select2</artifactId>
+        <version>${select2.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>org.webjars.bower</groupId>
+            <artifactId>jquery</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
+        <groupId>org.webjars.bower</groupId>
+        <artifactId>FileSaver.js</artifactId>
+        <version>${FileSaver.version}</version>
+      </dependency>
+
+
+      <dependency>
+        <groupId>com.beust</groupId>
+        <artifactId>jcommander</artifactId>
+        <version>1.47</version>
+      </dependency>
       
       <dependency>
         <groupId>org.codehaus.izpack</groupId>
@@ -1376,6 +1462,7 @@ under the License.
             <exclude>**/META-INF/cxf/**</exclude>
             <exclude>**/META-INF/services/**</exclude>
             <exclude>**/META-INF/MANIFEST.MF</exclude>            
+            <exclude>**/META-INF/resources/app/views/**</exclude>            
             <exclude>**/*.csv</exclude>
             <exclude>**/archetype-resources/**</exclude>
             <exclude>**/AdminLTE*/**</exclude>


[2/4] syncope git commit: SYNCOPE-701 first working implementation

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif b/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif
new file mode 100644
index 0000000..766cf24
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif differ

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif b/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif
new file mode 100644
index 0000000..e77264f
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif differ

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png b/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png
new file mode 100644
index 0000000..aa2f3e2
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png differ

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png b/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png
new file mode 100644
index 0000000..c57b86c
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png differ

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png b/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png
new file mode 100644
index 0000000..f05105e
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png differ

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/index.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html
new file mode 100644
index 0000000..6cb7ae6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -0,0 +1,116 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<!DOCTYPE html>
+<!--[if lt IE 7]>      <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]>         <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]>         <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html lang="en" ng-app="SyncopeEnduserApp" class="no-js"> <!--<![endif]-->
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>SyncopeEnduserApp</title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!--<link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/normalize.css">-->
+    <!--<link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/main.css">-->
+    <link rel="stylesheet" href="css/app.css">
+    <!--<script src="bower_components/html5-boilerplate/dist/js/vendor/modernizr-2.8.3.min.js"></script>-->
+  </head>
+  <body ng-cloak >
+    <!--<button ng-click=""-->
+
+    <!--[if lt IE 7]>
+        <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+    <![endif]-->
+
+    <!--<div ng-view ng-cloak ng-controller="ApplicationController"></div>-->
+    <div ui-view ng-cloak ng-controller="ApplicationController"></div>
+
+    <!--    <footer id="footer" class="hidden-print">
+          <ul class="nav pull-right">
+              <li>
+                Copyright &copy; 2015, Apache Syncope
+              </li>
+          </ul>
+        </footer>-->
+
+    <!--default global growl message-->
+    <!--<div growl></div>-->
+
+    <!--    <div class="hidden-print" id="initialLoaderDiv">
+          <img src="img/ajax-loader.gif" class="ajax-loader"/>
+        </div>-->
+
+    <!-- In production use:
+    <script src="//ajax.googleapis.com/ajax/libs/angularjs/x.x.x/angular.min.js"></script>
+    -->
+    <script type="text/javascript" src="../webjars/jquery/${jquery.version}/jquery.js"></script>
+    <script src="../webjars/angular/${angular.version}/angular.js"></script>
+    <script src="../webjars/angular-ui-router/${angular-ui-router.version}/angular-ui-router.js"></script>
+    <script src="../webjars/angular-animate/${angular-animate.version}/angular-animate.js"></script>
+    <script src="../webjars/angular-resource/${angular-resource.version}/angular-resource.js"></script>
+    <script src="../webjars/angular-cookies/${angular-cookies.version}/angular-cookies.js"></script>
+    <script src="../webjars/angular-sanitize/${angular-sanitize.version}/angular-sanitize.js"></script>
+    <script src="../webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js"></script>
+    <script src="../webjars/angular-ui-select/${angular-ui-select.version}/select.js"></script>
+    <script src="../webjars/angular-growl-2/${angular-growl-2.version}/angular-growl.js"></script>
+    <script type="text/javascript" src="../webjars/bootstrap-select/${bootstrap-select.version}/js/bootstrap-select.min.js"></script>
+    <script src="../webjars/FileSaver.js/${FileSaver.version}/FileSaver.js" type="text/javascript"></script>
+    <!--main angular application-->
+    <script src="js/app.js"></script>
+    <!--services-->
+    <script src="js/services/authService.js"></script>
+    <script src="js/services/userSelfService.js"></script>
+    <script src="js/services/schemaService.js"></script>
+    <script src="js/services/realmService.js"></script>
+    <script src="js/services/securityQuestionService.js"></script>
+    <!--controllers-->
+    <script src="js/controllers/HomeController.js"></script>
+    <script src="js/controllers/LoginController.js"></script>
+    <script src="js/controllers/LanguageController.js"></script>
+    <script src="js/controllers/UserController.js"></script>
+    <!--directives-->
+    <script src="js/directives/dynamicAttribute.js"></script>
+    <script src="js/directives/dynamicPlainAttributes.js"></script>
+    <script src="js/directives/dynamicDerivedAttributes.js"></script>
+    <script src="js/directives/dynamicVirtualAttributes.js"></script>
+    <script src="js/directives/navigationButtons.js"></script>
+    <script src="js/directives/loader.js"></script>
+    <script src="js/directives/equals.js"></script>
+    <!--filters-->
+    <script src="js/filters/propsFilter.js"></script>
+
+
+    <link rel="shortcut icon" href="img/favicon.png" type="image/png"/>
+    <link href="css/login.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/jquery-ui/${jquery-ui.version}/jquery-ui.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/bootstrap/${bootstrap.version}/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/bootstrap-select/${bootstrap-select.version}/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/font-awesome/${font-awesome.version}/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/ionicons/${ionicons.version}/css/ionicons.min.css" rel="stylesheet" type="text/css" />
+    <link href="../webjars/angular-ui-select/${angular-ui-select.version}/select.css" rel="stylesheet" type="text/css"/>
+    <link href="../webjars/angular-growl-2/${angular-growl-2.version}/angular-growl.css" rel="stylesheet" type="text/css"/>
+    <link href="../webjars/select2/${select2.version}/select2.css" rel="stylesheet" type="text/css"/>
+    <link href="css/app.css" rel="stylesheet" type="text/css" />
+    <link href="css/login.css" rel="stylesheet" type="text/css" />
+    <link href="css/editUser.css" rel="stylesheet" type="text/css" />
+
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
new file mode 100644
index 0000000..1a53f00
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -0,0 +1,283 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+ **/
+
+'use strict';
+
+angular.module('home', []);
+angular.module('login', []);
+angular.module('language', []);
+angular.module('self', []);
+
+// Declare app level module which depends on views, and components
+var app = angular.module('SyncopeEnduserApp', [
+  'ui.router',
+  'ui.bootstrap',
+  'ui.select',
+  'ngSanitize',
+  'ngAnimate',
+  'ngResource',
+  'ngCookies',
+  'angular-growl',
+  'home',
+  'login',
+  'language',
+  'self'
+]);
+
+app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'growlProvider',
+  function ($stateProvider, $urlRouterProvider, $httpProvider, growlProvider) {
+    // route configuration
+    $stateProvider
+            .state('home', {
+              url: '/',
+              templateUrl: 'views/self.html'
+            })
+            .state('self', {
+              url: '/self',
+              templateUrl: 'views/self.html'
+            })
+            .state('user-self-update', {
+              url: '/user-self-update',
+              templateUrl: 'views/home.html',
+              controller: 'HomeController',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            .state('create', {
+              url: '/self/create',
+              templateUrl: 'views/editUser.html'
+            })
+            // nested states 
+            // each of these sections will have their own view
+            // url will be nested (/self/create)
+            .state('create.credentials', {
+              url: '/credentials',
+              templateUrl: 'views/user-credentials.html'
+            })
+            .state('create.plainSchemas', {
+              url: '/plainSchemas',
+              templateUrl: 'views/user-plain-schemas.html'
+            })
+            .state('create.derivedSchemas', {
+              url: '/derivedSchemas',
+              templateUrl: 'views/user-derived-schemas.html'
+            })
+            .state('create.virtualSchemas', {
+              url: '/virtualSchemas',
+              templateUrl: 'views/user-virtual-schemas.html'
+            })
+            // url will be /self/create/schema
+            .state('create.groups', {
+              url: '/groups',
+              templateUrl: 'views/user-groups.html'
+            })
+            .state('create.resources', {
+              url: '/resources',
+              templateUrl: 'views/user-resources.html'
+            })
+            .state('update', {
+              url: '/self/update',
+              templateUrl: 'views/editUser.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            // nested states 
+            // each of these sections will have their own view
+            // url will be nested (/self/create)
+            .state('update.credentials', {
+              url: '/credentials',
+              templateUrl: 'views/user-credentials.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            .state('update.plainSchemas', {
+              url: '/plainSchemas',
+              templateUrl: 'views/user-plain-schemas.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            .state('update.derivedSchemas', {
+              url: '/derivedSchemas',
+              templateUrl: 'views/user-derived-schemas.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            .state('update.virtualSchemas', {
+              url: '/virtualSchemas',
+              templateUrl: 'views/user-virtual-schemas.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            // url will be /self/create/schema
+            .state('update.groups', {
+              url: '/groups',
+              templateUrl: 'views/user-groups.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            })
+            .state('update.resources', {
+              url: '/resources',
+              templateUrl: 'views/user-resources.html',
+              resolve: {
+                'authenticated': function (AuthenticationHelper) {
+                  return AuthenticationHelper.authenticated();
+                }
+              }
+            });
+
+    // catch all other routes
+    // send users to the home page 
+    $urlRouterProvider.otherwise('/');
+
+    // HTTP service configuration
+    $httpProvider.defaults.withCredentials = true;
+
+    $httpProvider.interceptors.push(function ($q, $rootScope, $location) {
+      var numLoadings = 0;
+      return {
+//        'request': function (config) {
+//          numLoadings++;
+//          // Show loader
+//          if (config.url.indexOf("skipLoader=true") == -1) {
+//            $rootScope.$broadcast("loader_show");
+//          }
+//          return config || $q.when(config);
+//        },
+//        'response': function (response) {
+//          if ((--numLoadings) === 0) {
+//            // Hide loader
+//            $rootScope.$broadcast("loader_hide");
+//          }
+//          return response || $q.when(response);
+//        },
+        'responseError': function (response) {
+          if (response.config.url.indexOf("acceptError=true") == -1) {
+            var status = response.status;
+            if (status == 401) {
+              console.log("ERROR " + status);
+//              $location.path("/self");
+            }
+            if (status == 403) {
+              console.log("UNAUTHORIZED " + status);
+//              $location.path("/self");
+            }
+            if (status == 400 || status == 404 || status == 412 || status == 500) {
+//              if (response.data.validationErrors != undefined) {
+//                for (var i in response.data.validationErrors) {
+//                  $rootScope.$broadcast('growlMessage', {text: response.data.validationErrors[i] || '', severity: 'error'});
+//                }
+//              } else if (response.data.message != undefined) {
+//                $rootScope.$broadcast('growlMessage', {text: response.data.message || '', severity: 'error'})
+//              }
+              console.log("GENERIC ERROR " + status);
+            }
+          }
+          return $q.reject(response);
+        }
+      };
+    });
+    
+    growlProvider.globalTimeToLive(10000);
+    growlProvider.globalPosition('bottom-left');
+    growlProvider.globalInlineMessages(true);
+    growlProvider.globalDisableIcons(true);
+    //to enable html in growl
+//    growlProvider.globalEnableHtml(true);
+  }]);
+
+app.run(['$rootScope', '$location', '$cookies', '$state',
+  function ($rootScope, $location, $cookies, $state) {
+    // main program
+    // keep user logged in after page refresh
+    // check if user is logged or not
+    $rootScope.currentUser = $cookies.get('currentUser') || null;
+//If the route change failed due to authentication error, redirect them out
+    $rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
+      if (rejection === 'Not Authenticated') {
+        $location.path('/self');
+      }
+    });
+
+//    $rootScope.$on('success', function (event, args) {
+//      console.log("IN CONFIG EVENTO: ", event);
+//      $rootScope.$broadcast("error", "success");
+//    });
+
+    $rootScope.$on('$stateChangeSuccess', function (event, toState) {
+      if (toState.name === 'create') {
+        $state.go('create.credentials');
+      } else if (toState.name === 'update') {
+        $state.go('update.credentials');
+      }
+    });
+//        $rootScope.$on('$locationChangeStart', function (event, next, current) {
+//            // redirect to login page if not logged in
+//            if ($location.path() !== '/self' && !$rootScope.globals.currentUser) {
+//                $location.path('/self');
+//            }
+//        });
+  }]);
+
+app.controller('ApplicationController', function ($scope) {
+// DO NOTHING
+//  $scope.$on('success', function (event, args) {
+//    console.log("IN CONFIG EVENTO: ", event)
+//    $scope.$broadcast("error", "success");
+//  });
+});
+
+app.factory('AuthenticationHelper', ['$q', '$rootScope',
+  function ($q, $rootScope) {
+    return {
+      authenticated: function () {
+
+        var currentUser = $rootScope.currentUser;
+
+        console.log("AuthenticationHelper, currentUser: ", currentUser);
+
+        if (angular.isDefined(currentUser) && currentUser) {
+          return true;
+        } else {
+          console.log("NOT AUTHENTICATED, REDIRECT TO LOGIN PAGE");
+          return $q.reject('Not Authenticated');
+        }
+      }
+    };
+  }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
new file mode 100644
index 0000000..bf86413
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
@@ -0,0 +1,39 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+ **/
+
+'use strict';
+
+angular.module("home").controller("HomeController", ['$scope', '$http', '$location', function ($scope, $http, $location) {
+    $scope.title = 'Hello world!';
+    $scope.subtitle = 'Hello world SUBTITLE!';
+    $scope.name = "";
+
+// check if user is logged or not, check session variables: if user isn't logged redirect to login page
+
+      console.log("SONO IN HomeController");
+      
+//      var isLogged = false;
+//      if (!isLogged) {
+//        console.log("REDIRECT TO LOGIN PAGE");
+////        window.location = "./self.html";
+//        $location.path("/self");
+//      }
+
+    
+  }]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
new file mode 100644
index 0000000..9e1fa6c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
@@ -0,0 +1,66 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('language')
+        .controller('LanguageController', function ($scope) {
+
+          $scope.languages = {
+            availableLanguages: [
+              {id: '1', name: 'Italiano'},
+              {id: '2', name: 'English'},
+              {id: '3', name: 'Portugese'}
+            ],
+            selectedLanguage: {id: '2', name: 'English'}
+          };
+
+          $scope.init = function () {
+//            MainService.settings().then(function (response) {
+//              $scope.mainSettings = response;
+//            });
+
+            console.log("Init language controller");
+          };
+
+          $scope.changeLanguage = function (language) {
+
+            console.log("Language changed to: ", language);
+            
+            $scope.languages.selectedLanguage = language;
+            
+//            $translate.use(langKey);
+//            LanguageService.switchLocale.query({language: langKey}, {}, function (response) {
+//              $scope.selectedLanguage.locale = langKey;
+//            });
+          };
+
+          this.retrieveLanguages = function () {
+//            LanguageService.language.query({}, function (response) {
+//              $scope.languages = response;
+//            });
+            console.log("Retriebìving available languages");
+          };
+
+
+          this.retrieveLanguages();
+
+
+        });
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
new file mode 100644
index 0000000..c962571
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
@@ -0,0 +1,93 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module("login").controller("LoginController", ['$scope', '$rootScope', '$http', '$location', '$cookies',
+  'AuthService', 'growl', function ($scope, $rootScope, $http, $location, $cookies, AuthService, growl) {
+
+    $scope.credentials = {
+      username: '',
+      password: '',
+      errorMessage: ''
+    };
+
+    $scope.login = function (credentials) {
+
+      console.log("CREDENTIALS FROM PAGE: ", credentials);
+      console.log("AUTHSERVICE: ", AuthService);
+
+      AuthService.login($scope.credentials).then(function (user) {
+        console.log("LOGIN SUCCESS FOR: ", user);
+        console.log("DOPO AVER SETTATO CURRENT USER: ", $rootScope.currentUser);
+        console.log("COOKIE CURRENT USER: ", $cookies.get('currentUser'));
+        // reset error message
+        $scope.credentials.errorMessage = '';
+        // got to update page
+        $location.path("/self/update");
+      }, function (response) {
+        console.log("LOGIN FAILED: ", response);
+        $scope.credentials.errorMessage = "Login failed: " + response;
+        growl.error($scope.credentials.errorMessage, {referenceId: 1});
+      });
+    };
+
+    $scope.logout = function () {
+
+      console.log("PERFORMING LOGOUT");
+
+      AuthService.logout().then(function (response) {
+        console.log("LOGOUT SUCCESS: ", response);
+      }, function () {
+        console.log("LOGOUT FAILED");
+      });
+    };
+
+    $scope.isLogged = function () {
+      return angular.isDefined($rootScope.currentUser) && $rootScope.currentUser;
+    };
+
+    $scope.selfCreate = function () {
+      $location.path("/self/create");
+    };
+
+    $scope.passwordReset = function () {
+      // TODO
+      console.log("NOT YET IMPLEMENTED")
+    };
+
+    $scope.errorAPI = function () {
+      $http.get("/syncope-enduser/api/error").success(function (data) {
+        console.log("errorAPI response: ", data);
+      });
+    };
+
+    $scope.sampleAPI = function () {
+      $http.get("/syncope-enduser/api/user-self").success(function (data) {
+        console.log("sampleAPI response: ", data);
+      });
+    };
+
+    $scope.schemaAPI = function () {
+      $http.get("/syncope-enduser/api/schema").success(function (data) {
+        console.log("schemaAPI response: ", data);
+      });
+    };
+
+  }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
new file mode 100644
index 0000000..892de21
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -0,0 +1,206 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module("self").controller("UserController", ['$scope', '$rootScope', '$location', 'AuthService',
+  'UserSelfService', 'SchemaService', 'RealmService', 'SecurityQuestionService', 'growl', function ($scope, $rootScope,
+          $location, AuthService, UserSelfService, SchemaService, RealmService, SecurityQuestionService, growl) {
+
+    $scope.user = {};
+    $scope.confirmPassword = {
+      value: ''
+    };
+    $scope.userFormValid = false;
+    $scope.createMode = $location.path().indexOf("/self/create") > -1;
+
+    $scope.availableRealms = [];
+    $scope.availableSecurityQuestions = [];
+
+    $scope.initialSecurityQuestion = undefined;
+
+    $scope.initUser = function () {
+
+      $scope.dynamicForm = {
+        plainSchemas: [],
+        derSchemas: [],
+        virSchemas: [],
+        selectedDerSchemas: [],
+        selectedVirSchemas: [],
+        errorMessage: '',
+        attributeTable: {}
+      };
+
+
+      var initSchemas = function () {
+        // initialization is done here synchronously to have all schema fields populated correctly
+        SchemaService.getUserSchemas().then(function (schemas) {
+          $scope.dynamicForm.plainSchemas = schemas.plainSchemas;
+          $scope.dynamicForm.derSchemas = schemas.derSchemas;
+          $scope.dynamicForm.virSchemas = schemas.virSchemas;
+
+          // initialize plain attributes
+          for (var i = 0; i < schemas.plainSchemas.length; i++) {
+
+            var plainSchemaKey = schemas.plainSchemas[i].key;
+
+            if (!$scope.user.plainAttrs[plainSchemaKey]) {
+
+              $scope.user.plainAttrs[plainSchemaKey] = {
+                schema: plainSchemaKey,
+                values: [],
+                readonly: schemas.plainSchemas[i].readonly
+              };
+
+              // initialize multivalue schema and support table: create mode, only first value
+              if (schemas.plainSchemas[i].multivalue) {
+                $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = {
+                  fields: [schemas.plainSchemas[i].key + "_" + 0]
+                };
+              }
+            } else {
+              // initialize multivalue schema and support table: update mode, all provided values
+              if (schemas.plainSchemas[i].multivalue) {
+                $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = {
+                  fields: [schemas.plainSchemas[i].key + "_" + 0]
+                };
+                // add other values
+                for (var j = 1; j < $scope.user.plainAttrs[plainSchemaKey].values.length; j++) {
+                  $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key].fields.push(schemas.plainSchemas[i].key + "_" + j);
+                }
+              }
+            }
+          }
+
+          // initialize derived attributes
+          for (var i = 0; i < schemas.derSchemas.length; i++) {
+
+            var derSchemaKey = schemas.derSchemas[i].key;
+
+            if ($scope.user.derAttrs[derSchemaKey]) {
+              $scope.dynamicForm.selectedDerSchemas.push(schemas.derSchemas[i]);
+            }
+          }
+
+          // initialize virtual attributes
+          for (var i = 0; i < schemas.virSchemas.length; i++) {
+
+            var virSchemaKey = schemas.virSchemas[i].key;
+
+            if ($scope.user.virAttrs[virSchemaKey]) {
+              $scope.dynamicForm.selectedVirSchemas.push(schemas.virSchemas[i]);
+            }
+          }
+
+        }, function () {
+          console.log("Error retrieving user schemas");
+        });
+        console.log("USER WITH ATTRTO: ", $scope.user);
+
+      };
+
+      var initSecurityQuestions = function () {
+        SecurityQuestionService.getAvailableSecurityQuestions().then(function (response) {
+          $scope.availableSecurityQuestions = response;
+        }, function () {
+          console.log("Error");
+        });
+      };
+
+      var initRealms = function () {
+        $scope.availableRealms = RealmService.getAvailableRealmsStub();
+      };
+
+      var initUserRealm = function () {
+        $scope.user.realm = RealmService.getUserRealm();
+      };
+
+
+      var readUser = function () {
+        UserSelfService.read().then(function (response) {
+          $scope.user = response;
+          $scope.user.password = undefined;
+          $scope.initialSecurityQuestion = $scope.user.securityQuestion;
+        }, function () {
+          console.log("Error");
+        });
+      };
+
+      if ($scope.createMode) {
+
+        $scope.user = {
+          username: '',
+          password: '',
+          realm: '',
+          securityQuestion: undefined,
+          securityAnswer: '',
+          plainAttrs: {},
+          derAttrs: {},
+          virAttrs: {}
+        };
+
+        // retrieve user realm or all available realms
+        initUserRealm();
+
+      } else {
+
+        // read user from syncope core
+        readUser();
+        // read user security question
+
+      }
+
+      initRealms();
+      //retrieve security available questions
+      initSecurityQuestions();
+      // initialize user attributes starting from any object schemas
+      initSchemas();
+
+    };
+
+    $scope.saveUser = function (user) {
+      console.log("Save user: ", user);
+
+      if ($scope.createMode) {
+
+        UserSelfService.create(user).then(function (response) {
+          console.log("Created user: ", response);
+          growl.success("User " + $scope.user.username + " successfully created", {referenceId: 1});
+          $location.path('/self');
+        }, function (response) {
+          console.log("Error during user creation: ", response);
+          growl.error("Error: " + response, {referenceId: 2});
+        });
+
+      } else {
+
+        UserSelfService.update(user).then(function (response) {
+          console.log("Updated user: ", response);
+          growl.success("User " + $scope.user.username + " successfully updated", {referenceId: 1});
+          $location.path('/self');
+        }, function (response) {
+          console.log("Error during user update: ", response);
+          growl.error("Error: " + response, {referenceId: 2});
+        });
+      }
+    };
+
+
+
+  }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
new file mode 100644
index 0000000..6a00507
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
@@ -0,0 +1,190 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+'use strict';
+
+angular.module('self')
+        .directive('dynamicAttribute', function ($filter) {
+          return {
+            restrict: 'E',
+            templateUrl: 'views/dynamicAttribute.html',
+            scope: {
+              schema: "=",
+              index: "=",
+              user: "="
+            },
+            controller: function ($scope, $element, $window) {
+              $scope.initAttribute = function (schema, index) {
+
+                switch (schema.type) {
+                  case "Long":
+                  case "Double":
+                    $scope.user.plainAttrs[schema.key].values[index] = Number($scope.user.plainAttrs[schema.key].values[index])
+                            || undefined;
+                    break;
+                  case "Enum":
+                    $scope.enumerationValues = [];
+                    var enumerationValuesSplitted = schema.enumerationValues.toString().split(";");
+                    for (var i = 0; i < enumerationValuesSplitted.length; i++) {
+                      $scope.enumerationValues.push(enumerationValuesSplitted[i]);
+                    }
+                    $scope.user.plainAttrs[schema.key].values[index] = $scope.user.plainAttrs[schema.key].values[index]
+                            || $scope.enumerationValues[0];
+                    break;
+                  case "Binary":
+
+                    $scope.userFile = $scope.userFile || '';
+                    //for multivalue fields 
+//                    $scope.fileInputId = "fileInputId_" + index;
+
+                    $element.bind("change", function (changeEvent) {
+                      $scope.$apply(function () {
+                        var reader = new FileReader();
+                        var file = changeEvent.target.files[0];
+                        $scope.userFile = file.name;
+                        reader.onload = function (readerEvt) {
+                          var binaryString = readerEvt.target.result;
+                          $scope.user.plainAttrs[schema.key].values[index] = btoa(binaryString);
+                        };
+                        reader.readAsBinaryString(file);
+                      });
+                    });
+
+                    $scope.download = function () {
+                      var byteString = atob($scope.user.plainAttrs[schema.key].values[index]);
+
+                      var ab = new ArrayBuffer(byteString.length);
+                      var ia = new Uint8Array(ab);
+                      for (var i = 0; i < byteString.length; i++) {
+                        ia[i] = byteString.charCodeAt(i);
+                      }
+
+                      var blob = new Blob([ia], {type: schema.mimeType});
+
+                      saveAs(blob, schema.key);
+                    };
+                    $scope.remove = function () {
+                      $scope.user.plainAttrs[schema.key].values.splice(index, 1);
+                      $scope.userFile = '';
+                      $("#fileInput").replaceWith($("#fileInput").clone(true));
+                    };
+                    break;
+                  case "Date":
+
+                    $scope.selectedDate = $scope.user.plainAttrs[schema.key].values[index];
+                    $scope.format = $scope.schema.conversionPattern;
+                    $scope.includeTimezone = false;
+                    if ($scope.schema.conversionPattern.indexOf(".SSS") > -1) {
+                      $scope.format = $scope.format.replace(".SSS", ".sss");
+                    }
+                    if ($scope.schema.conversionPattern.indexOf("Z") > -1) {
+                      $scope.includeTimezone = true;
+                      $scope.format = $scope.format.replace("Z", "");
+                    }
+                    if ($scope.schema.conversionPattern.indexOf("\'") > -1) {
+                      $scope.format = $scope.format.replace(new RegExp("\'", "g"), "");
+                    }
+
+                    $scope.bindDateToModel = function (selectedDate, format) {
+                      var newFormat = $scope.includeTimezone ? format.concat(" Z") : format;
+                      if (selectedDate) {
+                        selectedDate = $filter('date')(selectedDate, newFormat);
+                        var dateGood = selectedDate.toString();
+                        $scope.user.plainAttrs[schema.key].values[index] = dateGood;
+                      } else {
+                        $scope.user.plainAttrs[schema.key].values[index] = selectedDate;
+                      }
+                    };
+
+                    $scope.clear = function () {
+                      $scope.user.plainAttrs[schema.key].values[index] = null;
+                    };
+
+                    // Disable weekend selection
+                    $scope.disabled = function (date, mode) {
+                      // example if you want to disable weekends
+                      // return (mode === 'day' && (date.getDay() === 0 || date.getDay() === 6));
+                      return false;
+                    };
+
+                    $scope.toggleMin = function () {
+                      $scope.minDate = $scope.minDate ? null : new Date();
+                    };
+
+                    $scope.maxDate = new Date(2050, 5, 22);
+
+                    $scope.open = function ($event) {
+                      $scope.status.opened = true;
+                    };
+
+                    $scope.setDate = function (year, month, day) {
+                      $scope.user.plainAttrs[schema.key].values[index] = new Date(year, month, day);
+                    };
+
+                    $scope.dateOptions = {
+                      startingDay: 1
+                    };
+
+                    $scope.status = {
+                      opened: false
+                    };
+
+                    var tomorrow = new Date();
+                    tomorrow.setDate(tomorrow.getDate() + 1);
+                    var afterTomorrow = new Date();
+                    afterTomorrow.setDate(tomorrow.getDate() + 2);
+                    $scope.events =
+                            [
+                              {
+                                date: tomorrow,
+                                status: 'full'
+                              },
+                              {
+                                date: afterTomorrow,
+                                status: 'partially'
+                              }
+                            ];
+
+                    $scope.getDayClass = function (date, mode) {
+                      if (mode === 'day') {
+                        var dayToCheck = new Date(date).setHours(0, 0, 0, 0);
+
+                        for (var i = 0; i < $scope.events.length; i++) {
+                          var currentDay = new Date($scope.events[i].date).setHours(0, 0, 0, 0);
+
+                          if (dayToCheck === currentDay) {
+                            return $scope.events[i].status;
+                          }
+                        }
+                      }
+
+                    };
+                    break;
+
+                  case "Boolean":
+                    $scope.user.plainAttrs[schema.key].values[index] =
+                            Boolean($scope.user.plainAttrs[schema.key].values[index]) || false;
+                    break;
+
+                }
+              }
+              ;
+            },
+            replace: true
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
new file mode 100644
index 0000000..887b5c6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
@@ -0,0 +1,52 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+'use strict';
+
+angular.module('self')
+        .directive('dynamicDerivedAttributes', function () {
+          return {
+            restrict: 'E',
+            templateUrl: 'views/dynamicDerivedAttributes.html',
+            scope: {
+              dynamicForm: "=form",
+              user: "="
+            },
+            controller: function ($scope) {
+
+              $scope.addDerivedAttribute = function (item, model) {
+                var derSchemaKey = item.key;
+                console.log("ADDING DERIVED item: ", derSchemaKey);
+                $scope.user.derAttrs[derSchemaKey] = {
+                  schema: derSchemaKey,
+                  values: [],
+                  readonly: false
+                };
+
+              };
+
+              $scope.removeDerivedAttribute = function (item, model) {
+                var derSchemaKey = item.key;
+                console.log("REMOVING DERIVED item: ", derSchemaKey);
+                delete $scope.user.derAttrs[derSchemaKey];
+                
+              };
+
+            }
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
new file mode 100644
index 0000000..1a0a4c3
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
@@ -0,0 +1,45 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+'use strict';
+
+angular.module('self')
+        .directive('dynamicPlainAttributes', function (SchemaService) {
+            return {
+              restrict: 'E',
+              templateUrl: 'views/dynamicPlainAttributes.html',
+              scope: {
+                dynamicForm: "=form",
+                user: "="
+              },
+              controller: function ($scope) {
+
+                $scope.addAttributeField = function (plainSchemaKey) {
+                  console.log("ADDING: ", plainSchemaKey + "_" + ($scope.dynamicForm.attributeTable[plainSchemaKey].fields.length));
+                  $scope.dynamicForm.attributeTable[plainSchemaKey].fields.push(plainSchemaKey + "_" + ($scope.dynamicForm.attributeTable[plainSchemaKey].fields.length));
+                };
+
+                $scope.removeAttributeField = function (plainSchemaKey, index) {
+                  console.log("REMOVING FROM: " + plainSchemaKey + " ATTRIBUTE INDEX: " + index);
+                  $scope.dynamicForm.attributeTable[plainSchemaKey].fields.splice(index, 1);
+                  // clean user model
+                  $scope.user.plainAttrs[plainSchemaKey].values.splice(index, 1);
+                };
+              }
+            };
+          });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
new file mode 100644
index 0000000..62c1591
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
@@ -0,0 +1,52 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+'use strict';
+
+angular.module('self')
+        .directive('dynamicVirtualAttributes', function () {
+          return {
+            restrict: 'E',
+            templateUrl: 'views/dynamicVirtualAttributes.html',
+            scope: {
+              dynamicForm: "=form",
+              user: "="
+            },
+            controller: function ($scope) {
+
+              $scope.addVirtualAttribute = function (item, model) {
+                var virSchemaKey = item.key;
+                console.log("ADDING VIRTUAL item: ", virSchemaKey);
+                $scope.user.virAttrs[virSchemaKey] = {
+                  schema: virSchemaKey,
+                  values: [],
+                  readonly: false
+                };
+
+              };
+
+              $scope.removeVirtualAttribute = function (item, model) {
+                var virSchemaKey = item.key;
+                console.log("REMOVING VIRTUAL item: ", virSchemaKey);
+                delete $scope.user.virAttrs[virSchemaKey];
+                
+              };
+
+            }
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
new file mode 100644
index 0000000..54c2022
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
@@ -0,0 +1,49 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+angular.module('self')
+        .directive('equals', function () {
+          return {
+            restrict: 'A',
+            require: '?ngModel',
+            link: function (scope, elem, attrs, ngModel) {
+              if (!ngModel)
+                return; // do nothing if no ng-model
+
+              // watch own value and re-validate on change
+              scope.$watch(attrs.ngModel, function () {
+                validate();
+              });
+
+              // observe the other value and re-validate on change
+              attrs.$observe('equals', function (val) {
+                validate();
+              });
+
+              var validate = function () {
+                // values
+                var val1 = ngModel.$viewValue;
+                var val2 = attrs.equals;
+
+                // set validity
+                ngModel.$setValidity('equals', !val1 || !val2 || val1 === val2);
+              };
+            }
+          };
+        });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
new file mode 100644
index 0000000..603fb34
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
@@ -0,0 +1,32 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('SyncopeEnduserApp')
+        .directive("loader", function ($rootScope) {
+          return function ($scope, element, attrs) {
+            $scope.$on("loader_show", function () {
+              return element.show();
+            });
+            return $scope.$on("loader_hide", function () {
+              return element.hide();
+            });
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
new file mode 100644
index 0000000..ff3eebf
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
@@ -0,0 +1,31 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+'use strict';
+
+angular.module('self')
+        .directive('navigationButtons', function () {
+          return {
+            restrict: 'E',
+            templateUrl: 'views/navigationButtons.html',
+            scope: {
+              next: "@",
+              previous: "@"
+            }
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
new file mode 100644
index 0000000..4bf52b2
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
@@ -0,0 +1,102 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict'
+
+angular.module('self', [])
+        .directive('checkStrength', function () {
+          return {
+            replace: false,
+            restrict: 'EACM',
+            link: function (scope, iElement, iAttrs) {
+
+              var strength = {
+                colors: ['#F00', '#F90', '#FF0', '#9F0', '#0F0'],
+                mesureStrength: function (p) {
+
+                  var _force = 0;
+                  var _regex = /[$-/:-?{-~!"^_`\[\]]/g;
+
+                  var _lowerLetters = /[a-z]+/.test(p);
+                  var _upperLetters = /[A-Z]+/.test(p);
+                  var _numbers = /[0-9]+/.test(p);
+                  var _symbols = _regex.test(p);
+
+                  var _flags = [_lowerLetters, _upperLetters, _numbers, _symbols];
+                  var _passedMatches = $.grep(_flags, function (el) {
+                    return el === true;
+                  }).length;
+
+                  _force += 2 * p.length + ((p.length >= 10) ? 1 : 0);
+                  _force += _passedMatches * 10;
+
+                  // penality (short password)
+                  _force = (p.length <= 6) ? Math.min(_force, 10) : _force;
+
+                  // penality (poor variety of characters)
+                  _force = (_passedMatches == 1) ? Math.min(_force, 10) : _force;
+                  _force = (_passedMatches == 2) ? Math.min(_force, 20) : _force;
+                  _force = (_passedMatches == 3) ? Math.min(_force, 40) : _force;
+
+                  return _force;
+
+                },
+                getColor: function (s) {
+
+                  var idx = 0;
+                  if (s <= 10) {
+                    idx = 0;
+                  }
+                  else if (s <= 20) {
+                    idx = 1;
+                  }
+                  else if (s <= 30) {
+                    idx = 2;
+                  }
+                  else if (s <= 40) {
+                    idx = 3;
+                  }
+                  else {
+                    idx = 4;
+                  }
+
+                  return {idx: idx + 1, col: this.colors[idx]};
+
+                }
+              };
+
+              scope.$watch(iAttrs.checkStrength, function () {
+                if (scope.pw === '') {
+                  iElement.css({"display": "none"});
+                } else {
+                  var strength = strength.mesureStrength(scope.pw);
+                  var c = strength.getColor(strength);
+                  iElement.css({"display": "inline"});
+                  iElement.children('li')
+                          .css({"background": "#DDD"})
+                          .slice(0, c.idx)
+                          .css({"background": c.col});
+                }
+              });
+
+            },
+            template: ''
+          };
+        });
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js b/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
new file mode 100644
index 0000000..a092d0c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
@@ -0,0 +1,52 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict'
+
+angular.module("self")
+        .filter('propsFilter', function () {
+          return function (items, props) {
+            var out = [];
+
+            if (angular.isArray(items)) {
+              items.forEach(function (item) {
+                var itemMatches = false;
+
+                var keys = Object.keys(props);
+                for (var i = 0; i < keys.length; i++) {
+                  var prop = keys[i];
+                  var text = props[prop].toLowerCase();
+                  if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
+                    itemMatches = true;
+                    break;
+                  }
+                }
+
+                if (itemMatches) {
+                  out.push(item);
+                }
+              });
+            } else {
+              // Let the output be the input untouched
+              out = items;
+            }
+
+            return out;
+          };
+        });

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
new file mode 100644
index 0000000..3c3f7af
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
@@ -0,0 +1,74 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('login')
+        .factory('AuthService', ['$rootScope', '$resource', '$q', '$http', '$cookies',
+          function ($rootScope, $resource, $q, $http, $cookies) {
+
+            var authService = {};
+
+            var clearUserCookie = function () {
+              $rootScope.currentUser = null;
+              $cookies.remove('currentUser');
+            };
+
+            authService.login = function (credentials) {
+              return $http
+                      .post('/syncope-enduser/api/login', credentials)
+                      .then(function (response) {
+                        var username = response.data;
+                        $cookies.put('currentUser', username);
+                        $rootScope.currentUser = username;
+                        return username;
+                      }, function (response) {
+                        clearUserCookie();
+                        console.log("Something went wrong during login, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            authService.logout = function () {
+              return $http
+                      .get('/syncope-enduser/api/logout')
+                      .then(function (response) {
+                        clearUserCookie();
+                        return response;
+                      }, function (response) {
+                        clearUserCookie();
+                        console.log("Something went wrong during logout, exit with status: ", response);
+                      });
+            };
+
+            return authService;
+//            return {
+//              login: $resource('/syncope-enduser/api/login', {}, {
+//                do: {method: 'POST', params: {}, isArray: false}
+//              })
+//            };
+//            return {
+//              logout: $resource('/cradleDashboard/api/logout', {}, {
+//                query: {method: 'GET', params: {}, isArray: false}
+//              })
+//            };
+
+          }]);
+
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
new file mode 100644
index 0000000..356dc87
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
@@ -0,0 +1,47 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('self')
+        .factory('RealmService', ['$resource', '$q', '$http',
+          function ($resource, $q, $http) {
+
+            var realmService = {};
+
+            realmService.getAvailableRealmsStub = function () {
+              return  ["/"];
+            };
+
+            realmService.getAvailableRealms = function () {
+              return  $http.get("/syncope-enduser/api/realms")
+                      .then(function (response) {
+                        console.log("realms response: ", response);
+                        return response.data;
+                      }, function (response) {
+                        console.log("Something went wrong during realms retrieval, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            realmService.getUserRealm = function () {
+              return  "/";
+            };
+            return realmService;
+          }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
new file mode 100644
index 0000000..be9f510
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
@@ -0,0 +1,42 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('self')
+        .factory('SchemaService', ['$resource', '$q', '$http',
+          function ($resource, $q, $http) {
+
+            var schemaService = {};
+
+            schemaService.getUserSchemas = function () {
+
+              return  $http.get("/syncope-enduser/api/schemas")
+                      .then(function (response) {
+                        console.log("schemaAPI response: ", response);
+                        return response.data;
+                      }, function (response) {
+                        console.log("Something went wrong during schema retrieval, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+            return schemaService;
+          }]);
+
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
new file mode 100644
index 0000000..ff91f18
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
@@ -0,0 +1,41 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('self')
+        .factory('SecurityQuestionService', ['$resource', '$q', '$http',
+          function ($resource, $q, $http) {
+
+            var securityQuestionService = {};
+
+            securityQuestionService.getAvailableSecurityQuestions = function () {
+              return  $http.get("/syncope-enduser/api/securityQuestions")
+                      .then(function (response) {
+                        console.log("security questions response: ", response);
+                        return response.data;
+                      }, function (response) {
+                        console.log("Something went wrong during security questions retrieval, exit with status: ",
+                                response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            return securityQuestionService;
+          }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
new file mode 100644
index 0000000..3a99e7f
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
@@ -0,0 +1,69 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+'use strict';
+
+angular.module('login')
+        .factory('UserSelfService', ['$resource', '$q', '$http',
+          function ($resource, $q, $http) {
+
+            var userSelfService = {};
+
+            userSelfService.read = function () {
+              return $http
+                      .get('/syncope-enduser/api/self/read')
+                      .then(function (response) {
+                        console.log("response read: ", response.data);
+                        return response.data;
+                      }, function (response) {
+                        console.log("Something went wrong during user self read, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            userSelfService.create = function (user) {
+              return $http
+                      .post('/syncope-enduser/api/self/create', user)
+                      .then(function (response) {
+                        console.log("response save: ", response)
+                        var username = response;
+                      }, function (response) {
+                        console.log("Something went wrong during user self creation, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            userSelfService.update = function (user) {
+              return $http
+                      .post('/syncope-enduser/api/self/update', user)
+                      .then(function (response) {
+                        var username = response;
+                      }, function (response) {
+                        console.log("Something went wrong during user self update, exit with status: ", response);
+                        return $q.reject(response.data || response.statusText);
+                      });
+            };
+
+            userSelfService.passwordReset = function () {
+            };
+
+            return userSelfService;
+          }]);
+
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
new file mode 100644
index 0000000..9c6b1d9
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
@@ -0,0 +1,58 @@
+<div ng-switch="schema.type" >
+  <input ng-switch-when="String" class="form-control" type="text"
+         ng-model="user.plainAttrs[schema.key].values[index]"
+         ng-required="schema.mandatoryCondition" 
+         ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)"/>
+  <input ng-switch-when="Encrypted" class="form-control" type="text"
+         ng-model="user.plainAttrs[schema.key].values[index]"
+         ng-required="schema.mandatoryCondition" 
+         ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)"/>
+  <div ng-switch-when="Boolean">
+    <input type="checkbox" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition" 
+           ng-init="initAttribute(schema, index)" />
+  </div>
+  <input ng-switch-when="Long" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition"
+         ng-init="initAttribute(schema, index)" />
+  <input ng-switch-when="Double" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition"
+         ng-init="initAttribute(schema, index)" />
+  <p ng-switch-when="Date" class="input-group" >
+    <input type="text" class="form-control" 
+           uib-datepicker-popup="{{format}}"
+           ng-model="selectedDate"
+           ng-change="bindDateToModel(selectedDate, format)"
+           min-date="minDate" max-date="maxDate"
+           is-open="status.opened" datepicker-options="dateOptions"
+           ng-required="schema.mandatoryCondition" close-text="Close" ng-init="initAttribute(schema, index)"/>
+    <span class="input-group-btn">
+      <button type="button" class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
+    </span>
+  </p>
+
+  <div ng-switch-when="Enum" ng-init="initAttribute(schema, index)">
+    <select class="form-control"
+            ng-model="user.plainAttrs[schema.key].values[index]"
+            ng-required="schema.mandatoryCondition">
+      <option ng-repeat="value in enumerationValues" value="{{value}}">{{schema.enumerationKeys[$index] || value}}</option>
+    </select>
+  </div>
+
+  <div ng-switch-when="Binary" ng-init="initAttribute(schema, index)">
+    <div enctype="multipart/form-data" accept-charset="UTF-8">
+      <input id="fileInput" type="file" ng-required="schema.mandatoryCondition"/>
+      <button type="button" title="Download file" class="fileButton btn btn-default btn-sm" ng-click="download()">
+        <i class="glyphicon glyphicon-download" ></i>
+      </button>
+      <button type="button" class="fileButton btn btn-default btn-sm" title="Remove file" ng-click="remove()">
+        <i class="glyphicon glyphicon-remove-sign" ></i>
+      </button>
+      <h4><span class="label label-primary" ng-model="userFile">{{userFile}}</span></h4>
+    </div>
+    
+  </div>
+
+  <input ng-switch-default class="form-control" type="text"
+         ng-model="user.plainAttrs[schema.key].values[index]"
+         ng-required="schema.mandatoryCondition" 
+         ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)"/>
+
+</div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
new file mode 100644
index 0000000..9400877
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
@@ -0,0 +1,21 @@
+<ui-select on-select="addDerivedAttribute($item, $model)" on-remove="removeDerivedAttribute($item, $model)" multiple
+           ng-model="dynamicForm.selectedDerSchemas" theme="select2" class="attribute-ui-select">
+  <ui-select-match placeholder="Select derived attribute...">{{$item.key}}</ui-select-match>
+  <ui-select-choices repeat="derSchema in dynamicForm.derSchemas | propsFilter: {key: $select.search}">
+    <div ng-bind-html="derSchema.key | highlight: $select.search"></div>
+    <small>
+      name: {{derSchema.key}}
+      expression: {{derSchema.expression}}
+    </small>
+  </ui-select-choices>
+</ui-select>
+
+<ul class="attribute-virtual-value-container">
+  <li class="attribute-virtual-value-field" ng-repeat="selectedDerSchema in dynamicForm.selectedDerSchemas| filter:q as results">
+    {{selectedDerSchema.key}}
+    <input style="font-weight: normal" class="form-control" type="text" ng-disabled="true" ng-model="user.derAttrs[selectedDerSchema.key].values[0]"/>
+  </li>
+  <li class="attribute-virtual-value-field" ng-if="results.length == 0">
+    <strong>No derived attributes selected...</strong>
+  </li>
+</ul>

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
new file mode 100644
index 0000000..074abbd
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
@@ -0,0 +1,22 @@
+<div id="attribute" class="form-group" ng-repeat="plainSchema in dynamicForm.plainSchemas">
+  <label for="plainSchema.key">{{plainSchema.key}} <span ng-if="Boolean(plainSchema.mandatoryCondition)">*</span></label>
+  <div ng-if="!plainSchema.multivalue">
+    <dynamic-attribute schema="plainSchema" user="user" index="0"></dynamic-attribute>
+  </div>
+
+  <div ng-if="plainSchema.multivalue">
+    <div ng-repeat="field in dynamicForm.attributeTable[plainSchema.key].fields track by $index" ng-model='dynamicForm.attributeTable[plainSchema.key].fields[$index]'>
+      <dynamic-attribute schema="plainSchema" user="user" index="$index"></dynamic-attribute>
+      <span>
+        <button class="btn btn-default btn-sm minus" ng-if="$index > 0" type="button" ng-click="removeAttributeField(plainSchema.key, $index)">
+          <i class="glyphicon glyphicon-minus" title="Remove value"></i>
+        </button>
+      </span>
+    </div>
+    <span>
+      <button class="btn btn-default btn-sm" type="button" ng-click="addAttributeField(plainSchema.key)">
+        <i class="glyphicon glyphicon-plus" title="Add value"></i>
+      </button>
+    </span>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
new file mode 100644
index 0000000..897eb2c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
@@ -0,0 +1,18 @@
+<ui-select on-select="addVirtualAttribute($item, $model)" on-remove="removeVirtualAttribute($item, $model)" multiple 
+           ng-model="dynamicForm.selectedVirSchemas" theme="select2" ng-disabled="false" class="attribute-ui-select">
+  <ui-select-match placeholder="Select virtual attribute...">{{$item.key}}</ui-select-match>
+  <ui-select-choices repeat="virSchema in dynamicForm.virSchemas | propsFilter: {key: $select.search}">
+    <div ng-bind-html="virSchema.key | highlight: $select.search"></div>
+  </ui-select-choices>
+</ui-select>
+
+<ul class="attribute-virtual-value-container">
+  <li class="attribute-virtual-value-field" ng-repeat="selectedVirSchema in dynamicForm.selectedVirSchemas| filter:q as results">
+    {{selectedVirSchema.key}}
+    <input style="font-weight: normal" class="form-control" type="text" ng-disabled="selectedVirSchema.readonly"
+            ng-model="user.virAttrs[selectedVirSchema.key].values[0]"/>
+  </li>
+  <li class="attribute-virtual-value-field" ng-if="results.length == 0">
+    <strong>No virtual attributes selected...</strong>
+  </li>
+</ul>
\ No newline at end of file


[3/4] syncope git commit: SYNCOPE-701 first working implementation

Posted by an...@apache.org.
SYNCOPE-701 first working implementation


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/223a64e2
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/223a64e2
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/223a64e2

Branch: refs/heads/master
Commit: 223a64e26deff69a4ed8275d0f1348ca4e130a01
Parents: 764fa2e
Author: Andrea Patricelli <an...@tirasa.net>
Authored: Mon Oct 5 15:12:55 2015 +0200
Committer: Andrea Patricelli <an...@tirasa.net>
Committed: Fri Oct 30 10:26:17 2015 +0100

----------------------------------------------------------------------
 client/enduser/pom.xml                          | 194 +++++++++
 .../enduser/SyncopeEnduserApplication.java      | 157 +++++++
 .../client/enduser/SyncopeEnduserSession.java   | 279 +++++++++++++
 .../client/enduser/adapters/UserTOAdapter.java  |  78 ++++
 .../client/enduser/model/Credentials.java       |  65 +++
 .../client/enduser/model/SchemaResponse.java    |  79 ++++
 .../client/enduser/model/UserTORequest.java     | 174 ++++++++
 .../syncope/client/enduser/pages/HomePage.java  |  35 ++
 .../enduser/resources/AbstractBaseResource.java |  58 +++
 .../client/enduser/resources/ErrorResource.java |  50 +++
 .../client/enduser/resources/LoginResource.java |  84 ++++
 .../enduser/resources/LogoutResource.java       |  43 ++
 .../enduser/resources/SchemaResource.java       | 116 ++++++
 .../resources/SecurityQuestionResource.java     |  73 ++++
 .../resources/UserSelfCreateResource.java       |  97 +++++
 .../enduser/resources/UserSelfReadResource.java |  66 +++
 .../resources/UserSelfUpdateResource.java       |  96 +++++
 .../META-INF/resources/app/css/app.css          |  28 ++
 .../META-INF/resources/app/css/editUser.css     | 253 ++++++++++++
 .../META-INF/resources/app/css/login.css        | 103 +++++
 .../META-INF/resources/app/img/ajax-loader.gif  | Bin 0 -> 1924 bytes
 .../META-INF/resources/app/img/busy.gif         | Bin 0 -> 2834 bytes
 .../META-INF/resources/app/img/favicon.png      | Bin 0 -> 641 bytes
 .../META-INF/resources/app/img/logo-green.png   | Bin 0 -> 12178 bytes
 .../META-INF/resources/app/img/logo.png         | Bin 0 -> 8913 bytes
 .../resources/META-INF/resources/app/index.html | 116 ++++++
 .../resources/META-INF/resources/app/js/app.js  | 283 +++++++++++++
 .../app/js/controllers/HomeController.js        |  39 ++
 .../app/js/controllers/LanguageController.js    |  66 +++
 .../app/js/controllers/LoginController.js       |  93 +++++
 .../app/js/controllers/UserController.js        | 206 +++++++++
 .../app/js/directives/dynamicAttribute.js       | 190 +++++++++
 .../js/directives/dynamicDerivedAttributes.js   |  52 +++
 .../app/js/directives/dynamicPlainAttributes.js |  45 ++
 .../js/directives/dynamicVirtualAttributes.js   |  52 +++
 .../resources/app/js/directives/equals.js       |  49 +++
 .../resources/app/js/directives/loader.js       |  32 ++
 .../app/js/directives/navigationButtons.js      |  31 ++
 .../js/directives/passwordStrengthEstimator.js  | 102 +++++
 .../resources/app/js/filters/propsFilter.js     |  52 +++
 .../resources/app/js/services/authService.js    |  74 ++++
 .../resources/app/js/services/realmService.js   |  47 +++
 .../resources/app/js/services/schemaService.js  |  42 ++
 .../app/js/services/securityQuestionService.js  |  41 ++
 .../app/js/services/userSelfService.js          |  69 ++++
 .../resources/app/views/dynamicAttribute.html   |  58 +++
 .../app/views/dynamicDerivedAttributes.html     |  21 +
 .../app/views/dynamicPlainAttributes.html       |  22 +
 .../app/views/dynamicVirtualAttributes.html     |  18 +
 .../META-INF/resources/app/views/editUser.html  |  73 ++++
 .../resources/app/views/generic-error.html      |  24 ++
 .../META-INF/resources/app/views/home.html      |  34 ++
 .../resources/app/views/navigationButtons.html  |   8 +
 .../META-INF/resources/app/views/self.html      | 131 ++++++
 .../resources/app/views/user-credentials.html   |  60 +++
 .../app/views/user-derived-schemas.html         |  37 ++
 .../resources/app/views/user-groups.html        |  37 ++
 .../resources/app/views/user-plain-schemas.html |  37 ++
 .../resources/app/views/user-resources.html     |  28 ++
 .../app/views/user-virtual-schemas.html         |  37 ++
 .../main/resources/META-INF/web-fragment.xml    |  72 ++++
 .../src/main/resources/enduser.properties       |  30 ++
 .../syncope/client/enduser/pages/HomePage.html  |  22 +
 .../enduser/SyncopeEnduserApplicationTest.java  |  69 ++++
 client/pom.xml                                  |   1 +
 .../syncope/common/lib/types/Entitlement.java   |  10 -
 .../syncope/core/logic/AnyTypeClassLogic.java   |   4 +-
 .../apache/syncope/core/logic/AnyTypeLogic.java |   4 +-
 .../apache/syncope/core/logic/SchemaLogic.java  |   2 +-
 .../core/reference/AuthenticationITCase.java    |  11 -
 fit/enduser-reference/pom.xml                   | 413 +++++++++++++++++++
 .../src/main/resources/context.xml              |  23 ++
 .../src/main/resources/enduser.properties       |  30 ++
 .../src/main/resources/log4j2.xml               |  58 +++
 .../src/main/webapp/WEB-INF/glassfish-web.xml   |  25 ++
 .../WEB-INF/jboss-deployment-structure.xml      |  37 ++
 .../src/main/webapp/WEB-INF/weblogic.xml        |  35 ++
 fit/pom.xml                                     |   1 +
 pom.xml                                         |  89 +++-
 79 files changed, 5343 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/pom.xml
----------------------------------------------------------------------
diff --git a/client/enduser/pom.xml b/client/enduser/pom.xml
new file mode 100644
index 0000000..a9dc260
--- /dev/null
+++ b/client/enduser/pom.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>org.apache.syncope</groupId>
+    <artifactId>syncope-client</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+    
+  <name>Apache Syncope Client Enduser</name>
+  <description>Apache Syncope Client Enduser</description>
+  <groupId>org.apache.syncope.client</groupId>
+  <artifactId>syncope-client-enduser</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+  </properties>
+  
+  <dependencies>
+    
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-misc</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency> 
+      <groupId>javax.servlet</groupId> 
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket</artifactId>
+      <type>pom</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-extensions</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-datetime</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-spring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-auth-roles</artifactId>
+    </dependency>
+    
+    <!--AngularJS-->    
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular-route</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular-resource</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>angular-ui-router</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular-animate</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular-cookies</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>angular-growl-2</artifactId>
+    </dependency>
+    <!--Bootstrap-->
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>font-awesome</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>bootstrap-select</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>bootstrap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>ionicons</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>angular-ui-bootstrap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>angular-ui-select</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>angular-sanitize</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>select2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars.bower</groupId>
+      <artifactId>FileSaver.js</artifactId>
+    </dependency>
+
+    <!--Jquery-->
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>jquery</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>jquery-cookie</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.webjars</groupId>
+      <artifactId>jquery-ui</artifactId>
+    </dependency>
+    
+    <!--Logging-->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.syncope.client</groupId>
+      <artifactId>syncope-client-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <!-- TEST -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+    
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+    
+  </build>
+  
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
new file mode 100644
index 0000000..4acc756
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser;
+
+import java.io.Serializable;
+import org.apache.syncope.client.enduser.pages.HomePage;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import org.apache.syncope.client.enduser.resources.ErrorResource;
+import org.apache.syncope.client.enduser.resources.LoginResource;
+import org.apache.syncope.client.enduser.resources.LogoutResource;
+import org.apache.syncope.client.enduser.resources.SchemaResource;
+import org.apache.syncope.client.enduser.resources.SecurityQuestionResource;
+import org.apache.syncope.client.enduser.resources.UserSelfCreateResource;
+import org.apache.syncope.client.enduser.resources.UserSelfReadResource;
+import org.apache.syncope.client.enduser.resources.UserSelfUpdateResource;
+import org.apache.wicket.Page;
+import org.apache.wicket.Session;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SyncopeEnduserApplication extends WebApplication implements Serializable {
+
+    private static final long serialVersionUID = -6445919351044845120L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(SyncopeEnduserApplication.class);
+
+    public static final List<Locale> SUPPORTED_LOCALES = Collections.unmodifiableList(Arrays.asList(
+            new Locale[] {
+                Locale.ENGLISH, Locale.ITALIAN, new Locale("pt", "BR")
+            }));
+
+    @Override
+    protected void init() {
+        super.init();
+
+        LOG.debug("init SyncopeEnduserApplication");
+
+        // resource to provide login functionality managed by wicket
+        mountResource("/api/login", new ResourceReference("login") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new LoginResource();
+            }
+        });
+
+        // resource to provide logout functionality managed by wicket
+        mountResource("/api/logout", new ResourceReference("logout") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new LogoutResource();
+            }
+        });
+
+        // resource to retrieve info about logged user
+        mountResource("/api/self/read", new ResourceReference("userSelfRead") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new UserSelfReadResource();
+            }
+        });
+
+        // resource to provide user self create functionality managed by wicket
+        mountResource("/api/self/create", new ResourceReference("userSelfCreate") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new UserSelfCreateResource();
+            }
+        });
+
+        // resource to provide user self update functionality managed by wicket
+        mountResource("/api/self/update", new ResourceReference("userSelfUpdate") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new UserSelfUpdateResource();
+            }
+        });
+
+        mountResource("/api/schemas", new ResourceReference("schemas") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new SchemaResource();
+            }
+        });
+        
+        mountResource("/api/securityQuestions", new ResourceReference("securityQuestions") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new SecurityQuestionResource();
+            }
+        });
+
+        mountResource("/api/error", new ResourceReference("error") {
+
+            private static final long serialVersionUID = -128426276529456602L;
+
+            @Override
+            public IResource getResource() {
+                return new ErrorResource();
+            }
+        });
+    }
+
+    @Override
+    public Class<? extends Page> getHomePage() {
+        return HomePage.class;
+    }
+
+    @Override
+    public Session newSession(final Request request, final Response response) {
+        return new SyncopeEnduserSession(request);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
new file mode 100644
index 0000000..c5abc1d
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.SyncopeTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+import org.apache.wicket.Session;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Custom Syncope Enduser Session class.
+ */
+public class SyncopeEnduserSession extends WebSession {
+
+    private static final long serialVersionUID = 1284946129513378647L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(SyncopeEnduserSession.class);
+
+    public static final List<Locale> SUPPORTED_LOCALES = Arrays.asList(new Locale[] {
+        Locale.ENGLISH, Locale.ITALIAN, new Locale("pt", "BR") });
+
+    protected static final String ENDUSER_PROPERTIES = "enduser.properties";
+
+    private String username;
+
+    private String password;
+
+    private String scheme;
+
+    private String host;
+
+    private String port;
+
+    private String rootPath;
+
+    private String anonymousUser;
+
+    private String anonymousKey;
+
+    private Boolean storePassword;
+
+    private String version;
+
+    private String license;
+
+    private final SyncopeClientFactoryBean clientFactory;
+
+    private SyncopeClient client;
+
+    private final SyncopeClient anonymousClient;
+
+    private final SyncopeTO syncopeTO;
+
+    private UserTO selfTO;
+
+    private final Map<Class<?>, Object> services = Collections.synchronizedMap(new HashMap<Class<?>, Object>());
+
+    public static SyncopeEnduserSession get() {
+        return (SyncopeEnduserSession) Session.get();
+    }
+
+    public SyncopeEnduserSession(final Request request) {
+        super(request);
+
+        // load properties from classpath file
+        loadProperties();
+
+        clientFactory = new SyncopeClientFactoryBean();
+        clientFactory.setAddress(new StringBuilder(scheme)
+                .append("://")
+                .append(host)
+                .append(":")
+                .append(port)
+                .append("/")
+                .append(rootPath)
+                .toString());
+        clientFactory.setContentType(SyncopeClientFactoryBean.ContentType.JSON);
+
+        anonymousClient = clientFactory.create(anonymousUser, anonymousKey);
+        syncopeTO = anonymousClient.getService(SyncopeService.class).info();
+
+    }
+
+    public boolean authenticate(final String username, final String password) {
+        boolean authenticated = false;
+
+        try {
+            client = clientFactory.setDomain(SyncopeConstants.MASTER_DOMAIN).create(username, password);
+
+            Pair<Map<String, Set<String>>, UserTO> self = client.self();
+            selfTO = self.getValue();
+
+            this.username = username;
+            this.password = password;
+            // bind explicitly this session to have a stateful behavior during http requests, unless session will expire
+            // for every  request
+            this.bind();
+            authenticated = true;
+        } catch (Exception e) {
+            LOG.error("Authentication failed", e);
+        }
+
+        return authenticated;
+    }
+
+    public <T> void resetClient(final Class<T> service) {
+        T serviceInstance = getCachedService(service);
+        WebClient.client(serviceInstance).reset();
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T getCachedService(final Class<T> serviceClass) {
+        T service;
+        if (services.containsKey(serviceClass)) {
+            service = (T) services.get(serviceClass);
+        } else {
+            service = client == null ? anonymousClient.getService(serviceClass) : client.getService(serviceClass);
+            services.put(serviceClass, service);
+        }
+
+        return service;
+    }
+
+    public <T> T getService(final Class<T> serviceClass) {
+        return getCachedService(serviceClass);
+    }
+
+    public <T> T getService(final String etag, final Class<T> serviceClass) {
+        T serviceInstance = getCachedService(serviceClass);
+        WebClient.client(serviceInstance).match(new EntityTag(etag), false).
+                type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
+
+        return serviceInstance;
+    }
+
+    public <T> T getService(final MediaType mediaType, final Class<T> serviceClass) {
+        T service;
+
+        synchronized (clientFactory) {
+            SyncopeClientFactoryBean.ContentType preType = clientFactory.getContentType();
+
+            clientFactory.setContentType(SyncopeClientFactoryBean.ContentType.fromString(mediaType.toString()));
+            service = clientFactory.create(username, password).getService(serviceClass);
+            clientFactory.setContentType(preType);
+        }
+
+        return service;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public String getScheme() {
+        return scheme;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public String getRootPath() {
+        return rootPath;
+    }
+
+    public String getAnonymousUser() {
+        return anonymousUser;
+    }
+
+    public String getAnonymousKey() {
+        return anonymousKey;
+    }
+
+    public Boolean storePassword() {
+        return this.storePassword;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getLicense() {
+        return license;
+    }
+
+    public SyncopeTO getSyncopeTO() {
+        return syncopeTO;
+    }
+
+    public UserTO getSelfTO() {
+        return selfTO;
+    }
+
+    public boolean isAuthenticated() {
+        return getUsername() != null;
+    }
+
+    public DateFormat getDateFormat() {
+        final Locale locale = getLocale() == null ? Locale.ENGLISH : getLocale();
+
+        return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
+    }
+
+    private void loadProperties() {
+        Properties properties = new Properties();
+
+        try {
+            properties.load(getClass().getResourceAsStream("/" + ENDUSER_PROPERTIES));
+            File enduserDir = new File(properties.getProperty("enduser.directory"));
+            if (enduserDir.exists() && enduserDir.canRead() && enduserDir.isDirectory()) {
+                File enduserDirProps = FileUtils.getFile(enduserDir, ENDUSER_PROPERTIES);
+                if (enduserDirProps.exists() && enduserDirProps.canRead() && enduserDirProps.isFile()) {
+                    properties.clear();
+                    properties.load(FileUtils.openInputStream(enduserDir));
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Error loading {} file", ENDUSER_PROPERTIES, e);
+//            throw new WicketRuntimeException("Could not read " + ENDUSER_PROPERTIES, e);
+        }
+
+        this.scheme = properties.getProperty("scheme");
+        this.host = properties.getProperty("host");
+        this.port = properties.getProperty("port");
+        this.rootPath = properties.getProperty("rootPath");
+        this.anonymousUser = properties.getProperty("anonymousUser");
+        this.anonymousKey = properties.getProperty("anonymousKey");
+        this.storePassword = Boolean.valueOf(properties.getProperty("storePassword"));
+        version = properties.getProperty("version");
+        license = properties.getProperty("license");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/UserTOAdapter.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/UserTOAdapter.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/UserTOAdapter.java
new file mode 100644
index 0000000..551555f
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/UserTOAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.adapters;
+
+import org.apache.syncope.client.enduser.model.UserTORequest;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserTOAdapter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserTOAdapter.class);
+
+    public UserTO fromUserTORequest(final UserTORequest userTORequest, final String oldSelfPassword) {
+
+        // adapter code, to be moved in a new utility class
+        final UserTO userTO = new UserTO();
+        // set key if in update mode
+        final Long key = userTORequest.getKey();
+        if (key != null) {
+            userTO.setKey(key);
+        }
+        // set username...
+        userTO.setUsername(userTORequest.getUsername());
+        // ...and password
+        String requestPassword = userTORequest.getPassword();
+        if (requestPassword == null || requestPassword.isEmpty()) {
+            userTO.setPassword(oldSelfPassword == null ? null : oldSelfPassword);
+        } else {
+            userTO.setPassword(requestPassword);
+        }
+
+        //set security question and answer
+        userTO.setSecurityQuestion(userTORequest.getSecurityQuestion());
+        userTO.setSecurityAnswer(userTORequest.getSecurityAnswer());
+        //set realm
+        userTO.setRealm(userTORequest.getRealm());
+        // add attributes
+        userTO.getPlainAttrs().addAll(userTORequest.getPlainAttrs().values());
+        userTO.getDerAttrs().addAll(userTORequest.getDerAttrs().values());
+        userTO.getVirAttrs().addAll(userTORequest.getVirAttrs().values());
+
+        return userTO;
+    }
+
+    public UserTORequest toUserTORequest(final UserTO userTO) {
+
+        final UserTORequest userTORequest = new UserTORequest().
+                key(userTO.getKey()).
+                username(userTO.getUsername()).
+                securityQuestion(userTO.getSecurityQuestion()).
+                securityAnswer(userTO.getSecurityAnswer()).
+                realm(userTO.getRealm());
+
+        userTORequest.getPlainAttrs().putAll(userTO.getPlainAttrMap());
+        userTORequest.getDerAttrs().putAll(userTO.getDerAttrMap());
+        userTORequest.getVirAttrs().putAll(userTO.getVirAttrMap());
+
+        return userTORequest;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/Credentials.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/Credentials.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/Credentials.java
new file mode 100644
index 0000000..68e3106
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/Credentials.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Credentials {
+
+    private String username;
+
+    private String password;
+
+    public Credentials() {
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(final String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(final String password) {
+        this.password = password;
+    }
+
+    public Credentials username(final String username) {
+        this.username = username;
+        return this;
+    }
+
+    public Credentials password(final String password) {
+        this.password = password;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringBuilder.reflectionToString(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/SchemaResponse.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/SchemaResponse.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/SchemaResponse.java
new file mode 100644
index 0000000..912f287
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/SchemaResponse.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+
+public class SchemaResponse implements Serializable {
+
+    private static final long serialVersionUID = -8896862106241712829L;
+
+    private List<PlainSchemaTO> plainSchemas = new ArrayList<>();
+
+    private List<DerSchemaTO> derSchemas = new ArrayList<>();
+
+    private List<VirSchemaTO> virSchemas = new ArrayList<>();
+
+    public SchemaResponse() {
+    }
+
+    public List<PlainSchemaTO> getPlainSchemas() {
+        return plainSchemas;
+    }
+
+    public void setPlainSchemas(final List<PlainSchemaTO> plainSchemas) {
+        this.plainSchemas = plainSchemas;
+    }
+
+    public List<DerSchemaTO> getDerSchemas() {
+        return derSchemas;
+    }
+
+    public void setDerSchemas(final List<DerSchemaTO> derSchemas) {
+        this.derSchemas = derSchemas;
+    }
+
+    public List<VirSchemaTO> getVirSchemas() {
+        return virSchemas;
+    }
+
+    public void setVirSchemas(final List<VirSchemaTO> virSchemas) {
+        this.virSchemas = virSchemas;
+    }
+
+    public SchemaResponse plainSchemas(final List<PlainSchemaTO> value) {
+        this.plainSchemas = value;
+        return this;
+    }
+
+    public SchemaResponse derSchemas(final List<DerSchemaTO> value) {
+        this.derSchemas = value;
+        return this;
+    }
+
+    public SchemaResponse virSchemas(final List<VirSchemaTO> value) {
+        this.virSchemas = value;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/UserTORequest.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/UserTORequest.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/UserTORequest.java
new file mode 100644
index 0000000..09bc219
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/UserTORequest.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.model;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public class UserTORequest implements Serializable {
+
+    private static final long serialVersionUID = -6763020920564016374L;
+
+    private Long key;
+
+    private String username;
+
+    private String password;
+
+    private Long securityQuestion;
+
+    private String securityAnswer;
+
+    private String realm;
+
+    private Map<String, AttrTO> plainAttrs = new HashMap<>();
+
+    private Map<String, AttrTO> derAttrs = new HashMap<>();
+
+    private Map<String, AttrTO> virAttrs = new HashMap<>();
+
+    public UserTORequest() {
+    }
+
+    public Long getKey() {
+        return key;
+    }
+
+    public void setKey(final Long key) {
+        this.key = key;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(final String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(final String password) {
+        this.password = password;
+    }
+
+    public Long getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    public void setSecurityQuestion(final Long securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(final String realm) {
+        this.realm = realm;
+    }
+
+    public Map<String, AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    public void setPlainAttrs(final Map<String, AttrTO> plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    public Map<String, AttrTO> getDerAttrs() {
+        return derAttrs;
+    }
+
+    public void setDerAttrs(final Map<String, AttrTO> derAttrs) {
+        this.derAttrs = derAttrs;
+    }
+
+    public Map<String, AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
+
+    public void setVirAttrs(final Map<String, AttrTO> virAttrs) {
+        this.virAttrs = virAttrs;
+    }
+
+    public UserTORequest key(final Long value) {
+        this.key = value;
+        return this;
+    }
+
+    public UserTORequest username(final String value) {
+        this.username = value;
+        return this;
+    }
+
+    public UserTORequest password(final String value) {
+        this.password = value;
+        return this;
+    }
+
+    public UserTORequest securityQuestion(final Long value) {
+        this.securityQuestion = value;
+        return this;
+    }
+
+    public UserTORequest securityAnswer(final String value) {
+        this.securityAnswer = value;
+        return this;
+    }
+
+    public UserTORequest realm(final String value) {
+        this.realm = value;
+        return this;
+    }
+
+    public UserTORequest plainAttrs(final Map<String, AttrTO> value) {
+        this.plainAttrs = value;
+        return this;
+    }
+
+    public UserTORequest derAttrs(final Map<String, AttrTO> value) {
+        this.derAttrs = value;
+        return this;
+    }
+
+    public UserTORequest virAttrs(final Map<String, AttrTO> value) {
+        this.virAttrs = value;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringBuilder.reflectionToString(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
new file mode 100644
index 0000000..4c5c07e
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/pages/HomePage.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.pages;
+
+import org.apache.wicket.NonResettingRestartException;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class HomePage extends WebPage {
+
+    private static final long serialVersionUID = -3422492668689122688L;
+
+    public HomePage(final PageParameters parameters) {
+        super(parameters);
+//        throw new RedirectToUrlException("/app/");
+        throw new NonResettingRestartException("/app/");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java
new file mode 100644
index 0000000..a3aedfc
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/AbstractBaseResource.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractBaseResource extends AbstractResource {
+
+    private static final long serialVersionUID = -7875801358718612782L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractBaseResource.class);
+
+    protected <T> T getService(final Class<T> serviceClass) {
+        return SyncopeEnduserSession.get().getService(serviceClass);
+    }
+
+    protected <T> T getService(final String etag, final Class<T> serviceClass) {
+        return SyncopeEnduserSession.get().getService(etag, serviceClass);
+    }
+
+    protected <T> void resetClient(final Class<T> serviceClass) {
+        SyncopeEnduserSession.get().resetClient(serviceClass);
+    }
+
+    protected boolean isSelfRegistrationAllowed() {
+        Boolean result = null;
+        try {
+            result = SyncopeEnduserSession.get().getSyncopeTO().isSelfRegAllowed();
+        } catch (SyncopeClientException e) {
+            LOG.error("While seeking if self registration is allowed", e);
+        }
+
+        return result == null
+                ? false
+                : result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ErrorResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ErrorResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ErrorResource.java
new file mode 100644
index 0000000..bfceeab
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ErrorResource.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import javax.ws.rs.core.MediaType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mirror REST resource for obtaining user self operations.
+ *
+ * @see org.apache.syncope.common.rest.api
+ */
+public class ErrorResource extends AbstractBaseResource {
+
+    private static final long serialVersionUID = -9184809392631523912L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ErrorResource.class);
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        ResourceResponse response = new ResourceResponse();
+        response.disableCaching();
+        response.setContentType(MediaType.APPLICATION_JSON);
+
+        response.setStatusCode(403);
+
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java
new file mode 100644
index 0000000..fa6fa8c
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LoginResource.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.enduser.model.Credentials;
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.util.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LoginResource extends AbstractBaseResource {
+
+    private static final long serialVersionUID = -7720997467070461915L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoginResource.class);
+
+    public LoginResource() {
+    }
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        int responseStatus;
+        final String responseMessage;
+        ResourceResponse response = new ResourceResponse();
+
+        try {
+            HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest();
+            Credentials credentials = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()),
+                    Credentials.class);
+            final String username = credentials.getUsername();
+            final String password = credentials.getPassword().isEmpty() ? null : credentials.getPassword();
+
+            LOG.debug("Enduser login, user: {}", username);
+
+            if (StringUtils.isBlank(username)) {
+                LOG.error("Could not read credentials from request: username is blank!");
+                responseMessage = "Could not read credentials from request: username is blank!";
+                responseStatus = 400;
+            } else {
+                // authenticate user
+                final boolean authenticated = SyncopeEnduserSession.get().authenticate(username, password);
+                responseStatus = authenticated ? 200 : 401;
+                responseMessage = username;
+            }
+
+            response.setWriteCallback(new WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(responseMessage);
+                }
+            });
+
+        } catch (Exception e) {
+            responseStatus = 400;
+            LOG.error("Could not read credentials from request", e);
+        }
+
+        response.setStatusCode(responseStatus);
+        return response;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java
new file mode 100644
index 0000000..545b44d
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/LogoutResource.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LogoutResource extends AbstractBaseResource {
+
+    private static final long serialVersionUID = -648841355644985051L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogoutResource.class);
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        LOG.debug("Enduser logout");
+        
+        SyncopeEnduserSession.get().invalidate();
+        
+        ResourceResponse response = new ResourceResponse();
+        response.setStatusCode(204);
+        return response;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
new file mode 100644
index 0000000..544138b
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.enduser.model.SchemaResponse;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.AnyTypeTO;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
+import org.apache.syncope.common.rest.api.service.AnyTypeService;
+import org.apache.syncope.common.rest.api.service.SchemaService;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SchemaResource extends AbstractBaseResource {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SchemaResource.class);
+
+    private static final long serialVersionUID = 6453101466981543020L;
+
+    private final AnyTypeService anyTypeService;
+
+    private final AnyTypeClassService anyTypeClassService;
+
+    private final SchemaService schemaService;
+
+    public SchemaResource() {
+        anyTypeService = getService(AnyTypeService.class);
+        anyTypeClassService = getService(AnyTypeClassService.class);
+        schemaService = getService(SchemaService.class);
+    }
+
+    @Override
+    protected AbstractResource.ResourceResponse newResourceResponse(final IResource.Attributes attributes) {
+
+        AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse();
+
+        int responseStatus = 200;
+
+        try {
+
+            final AnyTypeTO anyTypeUserTO = anyTypeService.read(AnyTypeKind.USER.name());
+
+            final List<PlainSchemaTO> plainSchemas = new ArrayList<>();
+            final List<DerSchemaTO> derSchemas = new ArrayList<>();
+            final List<VirSchemaTO> virSchemas = new ArrayList<>();
+
+            // read all USER type schemas
+            for (String clazz : anyTypeUserTO.getClasses()) {
+                plainSchemas.addAll(getSchemaTOs(anyTypeClassService.read(clazz).getPlainSchemas(), SchemaType.PLAIN,
+                        PlainSchemaTO.class));
+                derSchemas.addAll(getSchemaTOs(anyTypeClassService.read(clazz).getDerSchemas(), SchemaType.DERIVED,
+                        DerSchemaTO.class));
+                virSchemas.addAll(getSchemaTOs(anyTypeClassService.read(clazz).getVirSchemas(), SchemaType.VIRTUAL,
+                        VirSchemaTO.class));
+            }
+
+            response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+                @Override
+                public void writeData(final IResource.Attributes attributes) throws IOException {
+                    attributes.getResponse().write(POJOHelper.serialize(new SchemaResponse().
+                            plainSchemas(plainSchemas).
+                            derSchemas(derSchemas).
+                            virSchemas(virSchemas)));
+                }
+            });
+
+        } catch (Exception e) {
+            LOG.error("Error retrieving " + AnyTypeKind.USER.name() + " class schemas", e);
+            responseStatus = 400;
+        }
+
+        response.setStatusCode(responseStatus);
+        return response;
+    }
+
+    private <T extends AbstractSchemaTO> List<T> getSchemaTOs(final List<String> schemaNames,
+            final SchemaType schemaType, final Class<T> type) {
+
+        List<T> schemaTOs = new ArrayList<>();
+
+        for (String schemaName : schemaNames) {
+            schemaTOs.add(type.cast(schemaService.read(schemaType, schemaName)));
+        }
+
+        return schemaTOs;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
new file mode 100644
index 0000000..f1ab6c8
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import java.util.List;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SecurityQuestionResource extends AbstractBaseResource {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SecurityQuestionResource.class);
+
+    private static final long serialVersionUID = 6453101466981543020L;
+
+    private final SecurityQuestionService securityQuestionService;
+
+    public SecurityQuestionResource() {
+        securityQuestionService = getService(SecurityQuestionService.class);
+    }
+
+    @Override
+    protected AbstractResource.ResourceResponse newResourceResponse(final IResource.Attributes attributes) {
+
+        AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse();
+
+        int responseStatus = 200;
+
+        try {
+
+            LOG.debug("List available security questions");
+
+            final List<SecurityQuestionTO> securityQuestionTOs = securityQuestionService.list();
+
+            response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+                @Override
+                public void writeData(final IResource.Attributes attributes) throws IOException {
+                    attributes.getResponse().write(POJOHelper.serialize(securityQuestionTOs));
+                }
+            });
+
+        } catch (Exception e) {
+            LOG.error("Error retrieving security questions", e);
+            responseStatus = 400;
+        }
+
+        response.setStatusCode(responseStatus);
+        return response;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
new file mode 100644
index 0000000..61734a7
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.client.enduser.adapters.UserTOAdapter;
+import org.apache.syncope.client.enduser.model.UserTORequest;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.util.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserSelfCreateResource extends AbstractBaseResource {
+
+    private static final long serialVersionUID = -2721621682300247583L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserSelfCreateResource.class);
+
+    private final UserSelfService userSelfService;
+
+    private final UserTOAdapter userTOAdapter;
+
+    public UserSelfCreateResource() {
+        userTOAdapter = new UserTOAdapter();
+        userSelfService = getService(UserSelfService.class);
+    }
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        int responseStatus = 200;
+        final StringBuilder responseMessage = new StringBuilder();
+        ResourceResponse response = new ResourceResponse();
+
+        try {
+            HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest();
+
+            final UserTORequest userTORequest = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()),
+                    UserTORequest.class);
+
+            if (isSelfRegistrationAllowed() && userTORequest != null) {
+                LOG.debug("Received user self registration request for user: [{}]", userTORequest.getUsername());
+                LOG.trace("Received user self registration request is: [{}]", userTORequest);
+                // adapt request and create user
+                userSelfService.create(userTOAdapter.fromUserTORequest(userTORequest, null),
+                        SyncopeEnduserSession.get().storePassword());
+                responseMessage.append("User").append(userTORequest.getUsername()).append("created successfully");
+            } else {
+                responseMessage.append(userTORequest == null
+                        ? "Request received is not valid"
+                        : "Self registration not allowed");
+                responseStatus = 403;
+            }
+            response.setWriteCallback(new WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(responseMessage);
+                }
+            });
+
+        } catch (final Exception e) {
+            responseStatus = 400;
+            response.setWriteCallback(new WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(e.getMessage());
+                }
+            });
+            LOG.error("Could not read userTO from request", e);
+        }
+
+        response.setStatusCode(responseStatus);
+        return response;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
new file mode 100644
index 0000000..3519e78
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.client.enduser.adapters.UserTOAdapter;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mirror REST resource for obtaining user self operations.
+ *
+ * @see org.apache.syncope.common.rest.api
+ */
+public class UserSelfReadResource extends AbstractResource {
+
+    private static final long serialVersionUID = -9184809392631523912L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(UserSelfReadResource.class);
+
+    private final UserTOAdapter userTOAdapter;
+
+    public UserSelfReadResource() {
+        userTOAdapter = new UserTOAdapter();
+    }
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        ResourceResponse response = new ResourceResponse();
+        final String selfTOJson = POJOHelper.serialize(userTOAdapter.toUserTORequest(SyncopeEnduserSession.get().
+                getSelfTO()));
+
+        response.setWriteCallback(new WriteCallback() {
+
+            @Override
+            public void writeData(final Attributes attributes) throws IOException {
+                attributes.getResponse().write(selfTOJson);
+            }
+        });
+
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
new file mode 100644
index 0000000..5fc9c82
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.client.enduser.adapters.UserTOAdapter;
+import org.apache.syncope.client.enduser.model.UserTORequest;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.util.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserSelfUpdateResource extends AbstractBaseResource {
+
+    private static final long serialVersionUID = -2721621682300247583L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserSelfUpdateResource.class);
+
+    private final UserSelfService userSelfService;
+
+    private final UserTOAdapter userTOAdapter;
+
+    public UserSelfUpdateResource() {
+        userTOAdapter = new UserTOAdapter();
+        userSelfService = getService(UserSelfService.class);
+    }
+
+    @Override
+    protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+        int responseStatus = 200;
+        final String responseMessage;
+        ResourceResponse response = new ResourceResponse();
+
+        try {
+            HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest();
+
+            final UserTORequest userTOResponse = POJOHelper.deserialize(IOUtils.toString(request.getInputStream()),
+                    UserTORequest.class);
+
+            LOG.debug("userTOResponse: {}", userTOResponse);
+
+            // adapt user, change self password only value passed is not null and has changed
+            UserTO userTO = userTOAdapter.fromUserTORequest(userTOResponse, SyncopeEnduserSession.get().getPassword());
+
+            LOG.debug("Enduser user self update, user: {}", userTO.toString());
+
+            // update user
+            userSelfService.update(userTO);
+            responseMessage = "User updated successfully";
+
+            response.setWriteCallback(new WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(responseMessage);
+                }
+            });
+
+        } catch (final Exception e) {
+            responseStatus = 400;
+            response.setWriteCallback(new WriteCallback() {
+
+                @Override
+                public void writeData(final Attributes attributes) throws IOException {
+                    attributes.getResponse().write(e.getMessage());
+                }
+            });
+            LOG.error("Could not read userTO from request", e);
+        }
+
+        response.setStatusCode(responseStatus);
+        return response;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/app.css b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
new file mode 100644
index 0000000..e5ae8e5
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
@@ -0,0 +1,28 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+/* app general css stylesheet */
+
+.growl-container > .growl-item.ng-enter,
+.growl-container > .growl-item.ng-leave {
+  -webkit-transition:1s linear all;
+  -moz-transition:1s linear all;
+  -o-transition:1s linear all;
+  transition:1s linear all;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css b/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
new file mode 100644
index 0000000..ee13bd0
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
@@ -0,0 +1,253 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+#form-container {
+  position: relative;
+  width: 100%;
+  margin: 0 auto;
+  text-align: center;
+}
+
+#form-container .page-header   { background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+                                 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+                                 background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+                                 background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+                                 background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */ 
+                                 margin: 1% 16%;
+                                 width: 72%; padding:10px; 
+                                 /* shadows and rounded borders */
+                                 -moz-border-radius: 5px;
+                                 -webkit-border-radius: 5px;
+                                 border-radius: 5px;
+                                 -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
+                                 -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
+                                 box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
+}
+#form-container .breadcrumb-header   { 
+  margin: 1% 16%;
+  width: 72%; padding:10px; 
+}
+
+.signup-form {
+  text-align: left;
+  padding: 2%;
+}
+
+#attribute {
+  padding: 0 255px;
+}
+
+#attribute-derived,
+#attribute-virtual {
+  padding: 0 155px;
+}
+
+.attribute-virtual-value-container {
+  margin-top: 2%;
+  list-style: none;
+  padding-right: 5%;
+}
+
+.attribute-virtual-value-field {
+  font-weight: 700;
+  padding: 6px 12px;
+  margin-bottom: 2%;
+}
+
+.minus{
+  margin-bottom: 2%;
+}
+
+.fileButton{
+  margin-top: 2%;
+}
+
+.upper-select {
+  padding-right: 71%;
+  padding-left: 18%;
+}
+
+.attribute-ui-select {
+  width: 100%;
+  padding-right: 7%;
+  padding-left: 7%;
+}
+
+#previous {
+  background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */
+  float: left;
+  color: black;
+  width: 30%;
+}
+#previous:hover {
+  background: #658D5D;
+}
+
+#next{
+  background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */
+  margin-top: 5px;
+  float: right;
+  color: black;
+  width: 30%;
+}
+#next:hover {
+  background: #658D5D;
+}
+
+#save{
+  background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */
+  color: black;
+  margin-top: 5%;
+  width: 15%;
+}
+#save:hover {
+  background: #658D5D;
+}
+#cancel {
+  margin-top: 5%;
+  width: 15%;
+}
+
+#form-views             { width:auto; }
+
+/* basic styling for entering and leaving */
+/* left and right to add to ensure full width: position:absolute; left:30px; right:30px; */
+#form-views.ng-enter,
+#form-views.ng-leave      { 
+  transition:0.5s all ease; -moz-transition:0.5s all ease; -webkit-transition:0.5s all ease; 
+}
+
+/* enter animation */
+#form-views.ng-enter            { 
+  -webkit-animation:slideInRight 0.5s both ease;
+  -moz-animation:slideInRight 0.5s both ease;
+  animation:slideInRight 0.5s both ease; 
+}
+
+/* leave animation */
+#form-views.ng-leave            { 
+  -webkit-animation:slideOutLeft 0.5s both ease;
+  -moz-animation:slideOutLeft 0.5s both ease;
+  animation:slideOutLeft 0.5s both ease;   
+}
+
+/** Button breadcrumb **/
+.btn-breadcrumb .btn:not(:last-child):after {
+  content: " ";
+  display: block;
+  width: 0;
+  height: 0;
+  border-top: 17px solid transparent;
+  border-bottom: 17px solid transparent;
+  border-left: 10px solid white;
+  position: absolute;
+  top: 50%;
+  margin-top: -17px;
+  left: 100%;
+  z-index: 3;
+}
+.btn-breadcrumb .btn:not(:last-child):before {
+  content: " ";
+  display: block;
+  width: 0;
+  height: 0;
+  border-top: 17px solid transparent;
+  border-bottom: 17px solid transparent;
+  border-left: 10px solid rgb(173, 173, 173);
+  position: absolute;
+  top: 50%;
+  margin-top: -17px;
+  margin-left: 1px;
+  left: 100%;
+  z-index: 3;
+}
+
+/** The Spacing **/
+.btn-breadcrumb .btn {
+  padding:6px 12px 6px 24px;
+}
+.btn-breadcrumb .btn:first-child {
+  padding:6px 6px 6px 10px;
+}
+.btn-breadcrumb .btn:last-child {
+  padding:6px 18px 6px 24px;
+}
+
+/** Default button **/
+.btn-breadcrumb .btn.btn-default:not(:last-child):after {
+  border-left: 10px solid #fff;
+}
+.btn-breadcrumb .btn.btn-default:not(:last-child):before {
+  border-left: 10px solid #ccc;
+}
+.btn-breadcrumb .btn.btn-default:hover:not(:last-child):after {
+  border-left: 10px solid #ebebeb;
+}
+.btn-breadcrumb .btn.btn-default:hover:not(:last-child):before {
+  border-left: 10px solid #adadad;
+}
+
+.breadcrumb-disabled-link {
+  pointer-events: none;
+  cursor: default;
+}
+
+.text-validation-error{
+    color: #dd301b;
+    font-weight: 600;
+}
+/* ANIMATIONS
+============================================================================= */
+/* slide out to the left */
+@keyframes slideOutLeft {
+  to      { transform: translateX(-200%); }
+}
+@-moz-keyframes slideOutLeft {  
+  to      { -moz-transform: translateX(-200%); }
+}
+@-webkit-keyframes slideOutLeft {
+  to      { -webkit-transform: translateX(-200%); }
+}
+
+/* slide in from the right */
+@keyframes slideInRight {
+  from    { transform:translateX(200%); }
+  to      { transform: translateX(0); }
+}
+@-moz-keyframes slideInRight {
+  from    { -moz-transform:translateX(200%); }
+  to      { -moz-transform: translateX(0); }
+}
+@-webkit-keyframes slideInRight {
+  from    { -webkit-transform:translateX(200%); }
+  to      { -webkit-transform: translateX(0); }
+}
+

http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/css/login.css
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/login.css b/client/enduser/src/main/resources/META-INF/resources/app/css/login.css
new file mode 100644
index 0000000..fdc9e3e
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/css/login.css
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+body, html {
+  margin: 45px 0;
+  height: 100%;
+  background-repeat: no-repeat;
+  /*background-image: linear-gradient(rgb(104, 145, 162), #00a65a);*/
+  background-color: #EEEEEE;
+}
+#login-container {
+  position: relative;
+  width: 100%;
+  margin: 0 auto;
+  text-align: center;
+  background-color: #FFF;
+  border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.65);
+  box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.65);
+}
+#login-container .row > div {
+  margin-bottom: 1em;
+}
+#login-container .row > div:last-child {
+  margin-bottom: 0;
+}
+#login-container #logo {
+  position: relative;
+  float: left;
+  margin-left: 15%;
+  border-top-right-radius: 100px;
+  border-top-left-radius: 100px;
+  border-bottom-right-radius: 100px;
+  border-bottom-left-radius: 100px;
+}
+
+#login-container #language{
+  padding: 0px;
+  height: 40px;
+}
+
+#login-container #signup-btn {
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+#login-container #signup-btn:hover {
+  background-color: #1d1d1d;
+  border-color: #181818;
+}
+
+.login-btn {
+  background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */
+  margin-top: 5px;
+  color: black;
+}
+.login-btn:hover {
+  background: #658D5D;
+}
+
+#login {
+  position: relative;
+  padding: 25px 25px 50px 25px;
+  margin-bottom: 1em;
+}
+#login #login-form {
+  margin-top: 2em;
+  margin-bottom: 2em;
+  text-align: left;
+}
+#login-form{
+  padding: 0 195px;
+  margin: 7%;
+}
+#languageContainer {
+  padding: 0 25px;
+}
+
+.logout{
+  float: right;
+}
\ No newline at end of file


[4/4] syncope git commit: This closes #11

Posted by an...@apache.org.
This closes #11


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/714557e6
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/714557e6
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/714557e6

Branch: refs/heads/master
Commit: 714557e64f309bd4975ed55bb7d182a7727c4667
Parents: 223a64e
Author: Andrea Patricelli <an...@tirasa.net>
Authored: Fri Oct 30 10:31:21 2015 +0100
Committer: Andrea Patricelli <an...@tirasa.net>
Committed: Fri Oct 30 10:31:21 2015 +0100

----------------------------------------------------------------------
 pom.xml | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/714557e6/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a5ee74a..f4482f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1079,7 +1079,6 @@ under the License.
         <version>${FileSaver.version}</version>
       </dependency>
 
-
       <dependency>
         <groupId>com.beust</groupId>
         <artifactId>jcommander</artifactId>