diff --git a/MySQL_conf_pbx/test1/Rest-API-Postman/CezenPBX_API.postman_collection_Security.json b/MySQL_conf_pbx/test1/Rest-API-Postman/CezenPBX_API.postman_collection_Security.json
new file mode 100644
index 0000000..2c66ad7
--- /dev/null
+++ b/MySQL_conf_pbx/test1/Rest-API-Postman/CezenPBX_API.postman_collection_Security.json
@@ -0,0 +1,913 @@
+{
+ "info": {
+ "_postman_id": "721d5504-301f-488d-a25b-5e78769eac5a",
+ "name": "CezenPBX_API",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "29498098"
+ },
+ "item": [
+ {
+ "name": "create a new endpoint",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\": \"1005\",\n// \"transport\": \"transport-udp\",\n// \"context\": \"default\",\n// \"disallow\": \"all\",\n// \"allow\": \"ulaw,alaw\",\n// \"directMedia\": \"no\",\n \"connectedLineMethod\": null,\n \"callerid\": null,\n \"dtmfMode\": null,\n// \"mohsuggest\": \"default\",\n \"mailboxes\": null\n}\n\n// {\n// \"id\": \"1004\",\n// \"transport\": \"transport-udp\",\n// \"aors\": \"1004\",\n// \"auth\": \"1004\",\n// \"context\": \"default\",\n// \"disallow\": \"all\",\n// \"allow\": \"ulaw,alaw\",\n// \"directMedia\": \"no\",\n// \"connectedLineMethod\": null,\n// \"callerid\": \"User <1004>\",\n// \"dtmfMode\": null,\n// \"mohsuggest\": \"default\",\n// \"mailboxes\": \"1004@default\"\n// }",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_user",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_user"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "create a new extension",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"context\": \"default\",\n \"extension\": \"1005\",\n \"priority\": 1,\n \"app\": \"Dial\",\n \"appdata\": \"PJSIP/1005,20,m(default)\"\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_extension",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_extension"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "1005",
+ "originalRequest": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"context\": \"default\",\n \"extension\": \"1005\",\n \"priority\": 1,\n \"app\": \"Dial\",\n \"appdata\": \"PJSIP/1005,20,m(default)\"\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_extension",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_extension"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:20:09 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": false,\n \"message\": \"Data likely already exists or DB issue\",\n \"exceptionMessage\": \"could not execute statement [(conn=482) Duplicate entry '1005-PJSIP/1005,20,m(default)-1' for key 'extension_table_unique_val'] [insert into extensions_table (app,appdata,context,exten,priority) values (?,?,?,?,?)]; SQL [insert into extensions_table (app,appdata,context,exten,priority) values (?,?,?,?,?)]; constraint [extension_table_unique_val]\"\n}"
+ },
+ {
+ "name": "test1",
+ "originalRequest": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"context\": \"default\",\n \"extension\": \"test1\",\n \"priority\": 1,\n \"app\": \"Dial\",\n \"appdata\": \"test123rf\"\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_extension",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_extension"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:21:06 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": true,\n \"message\": \"test1 Persisted \",\n \"exceptionMessage\": \"\"\n}"
+ }
+ ]
+ },
+ {
+ "name": "set_password",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\": \"1005\",\n \"authType\": \"userpass\",\n \"userName\": \"1005\",\n \"password\": \"12345\",\n \"md5Cred\": null,\n \"realm\": null\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/set_password",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "set_password"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "set_password",
+ "originalRequest": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\": \"1005\",\n \"authType\": \"userpass\",\n \"userName\": \"1005\",\n \"password\": \"12345\",\n \"md5Cred\": null,\n \"realm\": null\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/set_password",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "set_password"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:21:54 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": false,\n \"message\": \"Endpoint and password already set \",\n \"exceptionMessage\": \"could not execute statement [(conn=482) Duplicate entry '1005' for key 'PRIMARY'] [insert into ps_auths (auth_type,md5_cred,password,realm,username,id) values (?,?,?,?,?,?)]; SQL [insert into ps_auths (auth_type,md5_cred,password,realm,username,id) values (?,?,?,?,?,?)]; constraint [PRIMARY]\"\n}"
+ }
+ ]
+ },
+ {
+ "name": "SetAORS",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\": \"1005\",\n \"maxContacts\": 1\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/set_aors",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "set_aors"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "SetAORS",
+ "originalRequest": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\": \"1005\",\n \"maxContacts\": 1\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/set_aors",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "set_aors"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:22:12 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": true,\n \"message\": \"1005 Persisted \",\n \"exceptionMessage\": \"\"\n}"
+ }
+ ]
+ },
+ {
+ "name": "DeleteExtension",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8081/cezen/delete_extension?sipNumber=testEndPoint",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "delete_extension"
+ ],
+ "query": [
+ {
+ "key": "sipNumber",
+ "value": "testEndPoint"
+ }
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "DeleteExtension",
+ "originalRequest": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8081/cezen/delete_extension?sipNumber=1005",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "delete_extension"
+ ],
+ "query": [
+ {
+ "key": "sipNumber",
+ "value": "1005"
+ }
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:22:35 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "true"
+ }
+ ]
+ },
+ {
+ "name": "Add_a_global_extension_feature",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"context\": \"default\",\n \"extension\": \"w\",\n \"priority\": 5,\n \"app\": \"Dial\",\n \"appdata\": \"W conf\"\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_feature",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_feature"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "Add_a_global_extension_feature",
+ "originalRequest": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"context\": \"default\",\n \"extension\": \"w\",\n \"priority\": 5,\n \"app\": \"Dial\",\n \"appdata\": \"W conf\"\n}\n",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/cezen/add_feature",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "cezen",
+ "add_feature"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 10:53:48 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": false,\n \"message\": \"w configured as default Already exists\",\n \"exceptionMessage\": \"jakarta.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call\"\n}"
+ }
+ ]
+ },
+ {
+ "name": "signup",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"userName\": \"Mathew Francis\",\n \"email\":\"asda@gmail.com\",\n \"password\": \"1234567890\",\n \"confirmPassword\": \"1234567890\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/open/signup",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "open",
+ "signup"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "login",
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "password",
+ "value": "1234",
+ "type": "string"
+ },
+ {
+ "key": "username",
+ "value": "mathew",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": ""
+ },
+ "url": {
+ "raw": "http://localhost:8081/open/login",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "open",
+ "login"
+ ]
+ }
+ },
+ "response": [
+ {
+ "name": "login",
+ "originalRequest": {
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": ""
+ },
+ "url": {
+ "raw": "http://localhost:8081/open/login",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "open",
+ "login"
+ ]
+ }
+ },
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ "header": [
+ {
+ "key": "Vary",
+ "value": "Origin"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Method"
+ },
+ {
+ "key": "Vary",
+ "value": "Access-Control-Request-Headers"
+ },
+ {
+ "key": "Set-Cookie",
+ "value": "Authorization=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJNYXRoZXcgRnJhbmNpcyIsInN1YiI6IkpXVF9Ub2tlbiIsInVzZXJuYW1lIjoiY29tLmV4YW1wbGUuY2V6ZW5QQlguZW50aXR5LnVzZXIuVXNlckVudGl0eUAzMGI5ZjFlOCIsImF1dGhvcml0aWVzIjoiUk9MRV9hZG1pbiIsImlhdCI6MTc0NzI5MDAyMCwiZXhwIjoxNzQ3MzIwMDIwfQ.kjyArki3Cbc90Jjf68pl5iPeg61GWaxb6yT6ivTNXes; Path=/; Secure; HttpOnly"
+ },
+ {
+ "key": "X-Content-Type-Options",
+ "value": "nosniff"
+ },
+ {
+ "key": "X-XSS-Protection",
+ "value": "0"
+ },
+ {
+ "key": "Cache-Control",
+ "value": "no-cache, no-store, max-age=0, must-revalidate"
+ },
+ {
+ "key": "Pragma",
+ "value": "no-cache"
+ },
+ {
+ "key": "Expires",
+ "value": "0"
+ },
+ {
+ "key": "X-Frame-Options",
+ "value": "DENY"
+ },
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Transfer-Encoding",
+ "value": "chunked"
+ },
+ {
+ "key": "Date",
+ "value": "Thu, 15 May 2025 06:20:20 GMT"
+ },
+ {
+ "key": "Keep-Alive",
+ "value": "timeout=60"
+ },
+ {
+ "key": "Connection",
+ "value": "keep-alive"
+ }
+ ],
+ "cookie": [],
+ "body": "{\n \"status\": false,\n \"message\": \"Login not yet implemented\",\n \"exceptionMessage\": \"Login not yet implemented\"\n}"
+ }
+ ]
+ },
+ {
+ "name": "logout",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8081/logout",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "logout"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/MySQL_conf_pbx/test1/db_asterisk/security.sql b/MySQL_conf_pbx/test1/db_asterisk/security.sql
new file mode 100644
index 0000000..951c79c
--- /dev/null
+++ b/MySQL_conf_pbx/test1/db_asterisk/security.sql
@@ -0,0 +1,102 @@
+USE asterisk_db;
+
+SHOW DATABASES;
+
+SHOW TABLES;
+
+
+SELECT * FROM `ps_endpoints`;
+
+DELETE FROM `ps_endpoints` WHERE `id` = '1004';
+
+SELECT * FROM `extensions_table`;
+DESCRIBE `extensions_table`;
+
+ALTER TABLE `extensions_table`
+ADD CONSTRAINT `extension_table_unique_val_two_check` UNIQUE (`exten`, `appdata`);
+
+
+ALTER TABLE `extensions_table`
+DROP INDEX `extension_table_unique_val`;
+
+
+ALTER TABLE `extensions_table`
+ADD CONSTRAINT `extension_table_unique_val` UNIQUE (`exten`, `appdata`, `priority`);
+
+DELETE FROM `extensions_table` WHERE priority = 4 and exten = "1005" ;
+DELETE FROM `extensions_table` WHERE exten = "1005" OR exten = "1004";
+
+DELETE FROM `ps_endpoints` WHERE id = "1004" OR id = "1005";
+DELETE FROM `extensions_table` WHERE exten = "1004" OR exten = "1005";
+
+DELETE FROM `ps_auths` WHERE id = "1004" OR id = "1005";
+DELETE FROM `ps_aors` WHERE id = "1004" OR id = "1005";
+
+SELECT * FROM `extensions_table` WHERE app = "Dial";
+SELECT * FROM extensions_table WHERE context = 'default' AND exten = '1005';
+SELECT * FROM extensions_table WHERE exten = '1004' AND context = 'default';
+
+
+
+SELECT * FROM `ps_endpoints`;
+SELECT * FROM `extensions_table`;
+--
+SELECT * FROM ps_auths;
+SELECT * FROM ps_aors;
+DESCRIBE `ps_auths`;
+DESCRIBE `ps_aors`;
+DESCRIBE `extensions_table`;
+
+INSERT INTO `ps_aors`(`id`,`max_contacts`) VALUES ("1004", 1);
+INSERT INTO `ps_auths`(`id`, `auth_type`, `username`, `password`, `md5_cred`, `realm`) VALUES("1004", "userpass", "1004", "12345", null, null);
+
+
+
+
+-- USER ROLES ROLE GOES HERE
+CREATE TABLE `roles`(
+`role_id` INTEGER NOT NULL AUTO_INCREMENT,
+`role_name` VARCHAR(20) UNIQUE NOT NULL,
+CONSTRAINT `roles_pk` PRIMARY KEY (`role_id`)
+)ENGINE = 'Innodb' AUTO_INCREMENT = 1, DEFAULT CHARSET 'latin1';
+
+DESCRIBE `roles`;
+
+
+CREATE TABLE `user_roles`(
+`u_id` INTEGER NOT NULL,
+`role_id` INTEGER NOT NULL,
+CONSTRAINT `user_roles_pk` PRIMARY KEY(`u_id`,`role_id`)
+)ENGINE = 'Innodb' AUTO_INCREMENT = 1, DEFAULT CHARSET 'latin1';
+
+
+-- foreign key to be added to this table in alter table form
+CREATE TABLE `user`(
+`u_id` INTEGER NOT NULL AUTO_INCREMENT,
+`user_name` VARCHAR(70) UNIQUE NOT NULL,
+`password` VARCHAR(68) NOT NULL,
+-- fk to uder_account
+CONSTRAINT `user_table_pk` PRIMARY KEY(`u_id`)
+)ENGINE = 'Innodb', AUTO_INCREMENT = 1, DEFAULT CHARSET 'latin1';
+
+ALTER TABLE `user` ADD COLUMN `user_email_id` VARCHAR(50) UNIQUE NOT NULL;
+
+
+ALTER TABLE `user_roles` ADD CONSTRAINT `user_lones_U_fk_to_user` FOREIGN KEY(`u_id`) REFERENCES `user`(`u_id`);
+ALTER TABLE `user_roles` ADD CONSTRAINT `user_lones_R_fk_to_user` FOREIGN KEY(`role_id`) REFERENCES `roles`(`role_id`);
+DESC `user_roles`;
+
+
+INSERT `roles`(`role_name`) VALUES ('ROLE_admin');
+
+SELECT * FROM `user`;
+SELECT * FROM `user_roles`;
+SELECT * FROM `roles`;
+
+DELETE FROM `user` WHERE `user_name` = 'Mathew Francis';
+DELETE FROM `user_roles` WHERE `u_id` = (SELECT `u_id` FROM `user_roles` LIMIT 1);
+DELETE FROM `roles` WHERE `roles`.`role_name` = 'ROLE_admin'
+
+
+
+
diff --git a/MySQL_conf_pbx/test1/mariadb_data/aria_log.00000001 b/MySQL_conf_pbx/test1/mariadb_data/aria_log.00000001
index 8b58be4..ed13395 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/aria_log.00000001 and b/MySQL_conf_pbx/test1/mariadb_data/aria_log.00000001 differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/aria_log_control b/MySQL_conf_pbx/test1/mariadb_data/aria_log_control
index e0a15ce..1a9d87a 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/aria_log_control and b/MySQL_conf_pbx/test1/mariadb_data/aria_log_control differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/extensions_table.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/extensions_table.ibd
index 929a38f..dda4fe9 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/extensions_table.ibd and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/extensions_table.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_aors.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_aors.ibd
index c053994..dd45690 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_aors.ibd and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_aors.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_auths.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_auths.ibd
index 1b36389..cad5e9c 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_auths.ibd and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_auths.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_endpoints.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_endpoints.ibd
index 2680add..bd717e1 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_endpoints.ibd and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/ps_endpoints.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.frm b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.frm
new file mode 100644
index 0000000..9ee21f9
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.frm differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.ibd
new file mode 100644
index 0000000..b92c3ff
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/roles.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.frm b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.frm
new file mode 100644
index 0000000..43809b8
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.frm differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.ibd
new file mode 100644
index 0000000..62121b3
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.frm b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.frm
new file mode 100644
index 0000000..1a6a76c
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.frm differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.ibd b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.ibd
new file mode 100644
index 0000000..2bfc8a1
Binary files /dev/null and b/MySQL_conf_pbx/test1/mariadb_data/asterisk_db/user_roles.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/ib_logfile0 b/MySQL_conf_pbx/test1/mariadb_data/ib_logfile0
index 13a022c..fc2e6b3 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/ib_logfile0 and b/MySQL_conf_pbx/test1/mariadb_data/ib_logfile0 differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/ibdata1 b/MySQL_conf_pbx/test1/mariadb_data/ibdata1
index 00f0192..b9cb7d2 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/ibdata1 and b/MySQL_conf_pbx/test1/mariadb_data/ibdata1 differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_index_stats.ibd b/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_index_stats.ibd
index 1ded65a..21e9201 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_index_stats.ibd and b/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_index_stats.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_table_stats.ibd b/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_table_stats.ibd
index 3380537..f6de378 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_table_stats.ibd and b/MySQL_conf_pbx/test1/mariadb_data/mysql/innodb_table_stats.ibd differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/undo001 b/MySQL_conf_pbx/test1/mariadb_data/undo001
index a665506..4007320 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/undo001 and b/MySQL_conf_pbx/test1/mariadb_data/undo001 differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/undo002 b/MySQL_conf_pbx/test1/mariadb_data/undo002
index f7bbda5..5230c87 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/undo002 and b/MySQL_conf_pbx/test1/mariadb_data/undo002 differ
diff --git a/MySQL_conf_pbx/test1/mariadb_data/undo003 b/MySQL_conf_pbx/test1/mariadb_data/undo003
index 174979c..ee69e21 100644
Binary files a/MySQL_conf_pbx/test1/mariadb_data/undo003 and b/MySQL_conf_pbx/test1/mariadb_data/undo003 differ
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/pom.xml b/MySQL_conf_pbx/test1/springCezenPBX/pom.xml
index 7489bb1..4b0f43d 100644
--- a/MySQL_conf_pbx/test1/springCezenPBX/pom.xml
+++ b/MySQL_conf_pbx/test1/springCezenPBX/pom.xml
@@ -70,6 +70,35 @@
org.springframework.boot
spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.3
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.3
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.3
+ runtime
+
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/BasicAsteriskOpsDAO.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/BasicAsteriskOpsDAO.java
index 34920d3..0f026b9 100644
--- a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/BasicAsteriskOpsDAO.java
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/BasicAsteriskOpsDAO.java
@@ -8,6 +8,7 @@ import jakarta.persistence.TypedQuery;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
+import org.springframework.transaction.UnexpectedRollbackException;
@Repository
public class BasicAsteriskOpsDAO implements CezenPbxOpsDAO {
@@ -114,21 +115,21 @@ public class BasicAsteriskOpsDAO implements CezenPbxOpsDAO {
}
@Override
- @Transactional
public ReturnStatus saveAnExtensionByCharacters(ExtensionsTable extensionsTable) {
-
- try{
-
- this.entityManager.persist(extensionsTable);
-
+ try {
+ this.doPersist(extensionsTable); // calls @Transactional method
return new ReturnStatus(true,
extensionsTable.getExtension() +" configured as "+ extensionsTable.getContext() +" added",
"");
-
- }catch (Exception e){
+ } catch (Exception e) {
return new ReturnStatus(false,
extensionsTable.getExtension() +" configured as "+ extensionsTable.getContext() +" Already exists",
e.toString());
}
}
+
+ @Transactional
+ public void doPersist(ExtensionsTable extensionsTable) {
+ entityManager.persist(extensionsTable);
+ }
}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAO.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAO.java
new file mode 100644
index 0000000..f998341
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAO.java
@@ -0,0 +1,18 @@
+package com.example.cezenPBX.DAO;
+
+import com.example.cezenPBX.DTO.ReturnStatus;
+import com.example.cezenPBX.entity.user.UserEntity;
+
+// TODO only one admin allowed ... once the admin creates an
+// account they should not be able to make the account again
+// admin login, logout and signup DAO operations
+public interface UserOpsDAO {
+
+ // check if user exists;
+ public boolean checkIfAdminExists(UserEntity userEntity) throws Exception;
+
+ // admin login
+ public ReturnStatus adminSetUsernameAndPassword(UserEntity userEntity);
+
+ public UserEntity getUserByUserName(String userName);
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAOImpl.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAOImpl.java
new file mode 100644
index 0000000..675f9f5
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DAO/UserOpsDAOImpl.java
@@ -0,0 +1,75 @@
+package com.example.cezenPBX.DAO;
+
+import com.example.cezenPBX.DTO.ReturnStatus;
+import com.example.cezenPBX.entity.user.Role;
+import com.example.cezenPBX.entity.user.UserEntity;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.Query;
+import jakarta.persistence.TypedQuery;
+import jakarta.transaction.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class UserOpsDAOImpl implements UserOpsDAO{
+
+ @Autowired
+ private EntityManager entityManager;
+
+ @Override
+ public boolean checkIfAdminExists(UserEntity userEntity){
+ // check if info exists in the database users table
+ // this enforces the fact that only one user can exist
+ Query query = entityManager.createQuery(
+ "SELECT COUNT(u) FROM UserEntity u JOIN u.roles r WHERE r.role = :roleName");
+ query.setParameter("roleName", "ROLE_Admin");
+ Long count = (Long) query.getSingleResult();
+ return count > 0;
+
+ }
+
+ // get roles from the database
+
+ // Admin sets a username and password for the first time
+ @Override
+ @Transactional
+ public ReturnStatus adminSetUsernameAndPassword(UserEntity userEntity) {
+
+ try {
+ if (checkIfAdminExists(userEntity)) {
+ return new ReturnStatus(false, "Admin already exists", "");
+ }
+ // Fetch existing ROLE_Admin from DB
+ TypedQuery query = entityManager.createQuery("FROM Role r WHERE r.role = :roleName", Role.class)
+ .setParameter("roleName", "ROLE_Admin");
+
+ Role role = query.getSingleResult();
+
+ userEntity.setARole(role);
+ // Persist the user
+ entityManager.persist(userEntity);
+ return new ReturnStatus(true, "Admin created", "");
+ } catch (Exception e) {
+ return new ReturnStatus(false, "Admin creation failed", e.getMessage());
+ }
+ }
+
+ // get user details by username
+ // throws an exception if the user doesn't exist
+ // exception is caught and returns null ... custom authentication provider must catch the exception
+ @Override
+ public UserEntity getUserByUserName(String userName) {
+
+ try{
+ TypedQuery query = this.entityManager
+ .createQuery("SELECT u FROM UserEntity u JOIN FETCH u.roles AS r WHERE u.userName = :userName", UserEntity.class);
+
+ query.setParameter("userName", userName);
+
+ return query.getSingleResult();
+
+ }catch ( Exception e){
+ return null;
+ }
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DTO/user/AdminSetPasswordDTO.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DTO/user/AdminSetPasswordDTO.java
new file mode 100644
index 0000000..a850c8f
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/DTO/user/AdminSetPasswordDTO.java
@@ -0,0 +1,20 @@
+package com.example.cezenPBX.DTO.user;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+
+public record AdminSetPasswordDTO(
+ @NotBlank(message = "Username cannot be blank")
+ String userName,
+
+ @Email(message = "Email is not valid")
+ String email,
+
+ @NotBlank(message = "Password cannot be blank")
+ @Size(min = 3, message = "Password must be at least 8 characters long")
+ String password,
+
+ @NotBlank(message = "Confirm password cannot be blank")
+ String confirmPassword
+) {}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CezenLoginSecurityChain.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CezenLoginSecurityChain.java
new file mode 100644
index 0000000..fec13ba
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CezenLoginSecurityChain.java
@@ -0,0 +1,112 @@
+package com.example.cezenPBX.config;
+
+
+import com.example.cezenPBX.security.JWTTokenGeneratorFilter;
+import com.example.cezenPBX.security.JWTTokenValidatorFilter;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
+import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+
+import java.util.Collections;
+import java.util.List;
+
+// this class will handel the routs that are protected and
+// allow spring security to accept login details from our custom login page
+@Configuration
+public class CezenLoginSecurityChain {
+
+ @Bean
+ SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
+
+ //the token is generated here
+ CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
+ requestHandler.setCsrfRequestAttributeName("_csrf");
+
+ //CSRF cookie
+ final CookieCsrfTokenRepository cookieCsrfTokenRepo = new CookieCsrfTokenRepository();
+ //make secure true when using only https
+ cookieCsrfTokenRepo.setCookieCustomizer(responseCookieBuilder -> responseCookieBuilder.secure(true));
+
+ // bellow line is used when you are using JWT tokens instead of jSession session keys but i put always because i guess CSRF token needs it
+ http.
+ logout((logout) -> logout.deleteCookies("Authorization", "JSESSIONID", "XSRF-TOKEN"))
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+
+ //now because we aare sending the JWT token to The UI Application in a Header
+ //we need to manage it in the CORs config
+ .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
+ @Override
+ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
+ //check CORs and CSRF in Previous commits
+ CorsConfiguration config = new CorsConfiguration();
+// config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
+ config.setAllowedOrigins(Collections.singletonList("*"));
+ config.setAllowedMethods(Collections.singletonList("*"));
+ config.setAllowCredentials(true);
+ config.setAllowedHeaders(Collections.singletonList("*"));
+ //the JWT will be sent to UI under Authorization header and XSR under X-XSRF-TOKEN
+ config.setExposedHeaders(List.of("Authorization", "X-XSRF-TOKEN"));
+ config.setMaxAge(3600L);
+ return config;
+ }
+ }))
+
+
+ //temporarily disabling cross sight resource forgery
+ .csrf(AbstractHttpConfigurer::disable)
+// .csrf((csrf) ->
+// csrf.csrfTokenRequestHandler(requestHandler).
+// ignoringRequestMatchers("/open/signup","/open/login","/user/getXSRfToken")
+// //.csrfTokenRepository(new CookieCsrfTokenRepository())
+// .csrfTokenRepository(cookieCsrfTokenRepo)
+// )
+ //.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class)
+
+ //token generation after BasicAuthenticationFilter.class
+ .addFilterAfter(new JWTTokenGeneratorFilter(), BasicAuthenticationFilter.class)
+ //then position the verification filter
+ .addFilterBefore(new JWTTokenValidatorFilter(), BasicAuthenticationFilter.class)
+ .authorizeHttpRequests((requests) -> requests
+ //only admin can use this rout
+ //user roles :- ROLE_admin ROLE_employee ROLE_manager ROLE_user
+ .requestMatchers(
+ "/cezen/add_user",
+ "/cezen/add_feature",
+ "/cezen/delete_extension",
+ "/cezen/set_aors",
+ "/cezen/set_password",
+ "/cezen/add_extension"
+ ).hasAnyRole("admin")
+ //any one who is authenticated can access /logout
+ .requestMatchers("/open/login", "/user/getXSRfToken", "/logout").authenticated()
+ //all the rest are open to public
+ .requestMatchers("/open/signup").permitAll()
+ //.requestMatchers(HttpMethod.POST, "/open/**").permitAll()
+ )
+ // redirect to /login if the user is not authenticated Customizer.withDefaults() enables a security feature using the defaults provided by Spring Security
+ .formLogin(Customizer.withDefaults())
+ .httpBasic(Customizer.withDefaults());
+
+ System.out.print("Security chain configured");
+ return http.build();
+
+ }
+
+ // to encode the password
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CustomAuthenticationProviderForCezen.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CustomAuthenticationProviderForCezen.java
new file mode 100644
index 0000000..f7edc02
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/config/CustomAuthenticationProviderForCezen.java
@@ -0,0 +1,81 @@
+package com.example.cezenPBX.config;
+
+import com.example.cezenPBX.DAO.UserOpsDAO;
+import com.example.cezenPBX.entity.user.UserEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class CustomAuthenticationProviderForCezen implements AuthenticationProvider {
+
+ @Autowired
+ private UserOpsDAO userOpsDAO;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+
+ //get credentials from login form
+ String username = authentication.getName();
+ String pwd = authentication.getCredentials().toString();
+
+ //sanity check
+ if (username.isEmpty() || pwd.isEmpty()) return null;
+
+ //check for employee
+ UserEntity user = null;
+ try {
+ //check if employee exists if yes then fetch details
+ user = this.userOpsDAO.getUserByUserName(username);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ return null;
+ }
+
+ if (passwordEncoder.matches(pwd, user.getPassword())) {
+
+ //then it is a match a number of springs granted authorities
+ List authorities = new ArrayList<>();
+
+ //loop through the users authorities and add each of them to simple granted authority
+ try {
+ //check if user is part of permission set for admin signing in
+ boolean isAdmin = false;
+ for(var permission : user.getRoles()){
+ if(permission.getRole().equals("ROLE_admin")) isAdmin = true;
+ }
+ if(!isAdmin) throw new BadCredentialsException("no employee permission for given employee");
+
+ user.getRoles().forEach(a -> authorities.add(new SimpleGrantedAuthority(a.getRole())));
+ } catch (Exception e) {
+ //use/**/r doesn't have permissions or roles = null
+ System.out.println(e.toString());
+ return null;
+ }
+
+ return new UsernamePasswordAuthenticationToken(user.getUserName(), pwd, authorities);
+ } else {
+ throw new BadCredentialsException("Invalid password!");
+ }
+ }
+
+ @Override
+ public boolean supports(Class> authentication) {
+ //tells spring that i want to support username password style of auth
+ return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
+ }
+
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/constents/SecurityConstants.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/constents/SecurityConstants.java
new file mode 100644
index 0000000..f72c978
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/constents/SecurityConstants.java
@@ -0,0 +1,7 @@
+package com.example.cezenPBX.constents;
+
+public interface SecurityConstants {
+
+ public static final String JWT_KEY = ";sdmn3426FHB426RH62389;]['/.sdwswa";
+ public static final String JWT_HEADER = "Authorization";
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/controller/SignUpController.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/controller/SignUpController.java
new file mode 100644
index 0000000..d982a11
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/controller/SignUpController.java
@@ -0,0 +1,38 @@
+package com.example.cezenPBX.controller;
+
+import com.example.cezenPBX.DTO.ReturnStatus;
+import com.example.cezenPBX.DTO.user.AdminSetPasswordDTO;
+import com.example.cezenPBX.service.PbxUserService;
+import jakarta.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/open")
+public class SignUpController {
+
+ @Autowired
+ private PbxUserService pbxUserService;
+
+ //sign up route
+ @PostMapping("/signup")
+ public ReturnStatus signUp(@RequestBody @Valid AdminSetPasswordDTO adminSetPasswordDTO){
+
+ return this.pbxUserService.adminSetUserNamePasswordSet(
+ adminSetPasswordDTO.userName(),
+ adminSetPasswordDTO.password(),
+ adminSetPasswordDTO.confirmPassword(),
+ adminSetPasswordDTO.email()
+ );
+ }
+
+ // and a login route
+ @GetMapping("/login")
+ public ReturnStatus login(){
+ return new ReturnStatus(true, "Welcome user authenticated successfully", "");
+ }
+
+
+
+ // forgot password
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/Role.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/Role.java
new file mode 100644
index 0000000..d79fbb6
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/Role.java
@@ -0,0 +1,65 @@
+package com.example.cezenPBX.entity.user;
+
+import jakarta.persistence.*;
+
+import java.util.Collection;
+
+@Entity
+@Table(name = "roles")
+final public class Role {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "role_id")
+ private int id;
+
+ //remember ROLE_
+ @Column(name = "role_name")
+ private String role;
+
+ //all employees under this role
+ // map by may be required
+ @ManyToMany(
+ fetch = FetchType.LAZY,
+ cascade = {
+ //The detach operation removes the entity from the persistent context. When we use CascadeType.DETACH, the child entity will also get removed from the persistent context.
+ CascadeType.DETACH,
+ CascadeType.MERGE,
+ CascadeType.PERSIST,
+ CascadeType.REFRESH,
+ }
+ //cascade = CascadeType.ALL
+ )
+ @JoinTable(
+ name = "user_roles",
+ joinColumns = @JoinColumn(name = "role_id"),
+ inverseJoinColumns = @JoinColumn(name = "u_id")
+ )
+ private Collection employees;
+
+ public Role(){}
+
+ public Role(String role) {
+ this.role = role;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public Collection getEmployees() {
+ return employees;
+ }
+
+ public void setEmployees(Collection employees) {
+ this.employees = employees;
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/UserEntity.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/UserEntity.java
new file mode 100644
index 0000000..b4ac6e4
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/entity/user/UserEntity.java
@@ -0,0 +1,90 @@
+package com.example.cezenPBX.entity.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.*;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+@Entity
+@Table(name = "user")
+final public class UserEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "u_id")
+ private int id;
+
+ @Column(name = "user_name")
+ private String userName;
+
+ @JsonIgnore
+ @Column(name = "password")
+ private String password;
+
+ @Column(name = "user_email_id")
+ private String email;
+
+ //ROLE
+ @ManyToMany(
+ fetch = FetchType.LAZY,
+ cascade = {
+ //The detach operation removes the entity from the persistent context. When we use CascadeType.DETACH, the child entity will also get removed from the persistent context.
+ CascadeType.DETACH,
+ CascadeType.MERGE,
+ CascadeType.PERSIST,
+ CascadeType.REFRESH,
+ }
+ //cascade = CascadeType.ALL
+ )
+ @JoinTable(
+ name = "user_roles",
+ joinColumns = @JoinColumn(name = "u_id"),
+ inverseJoinColumns = @JoinColumn(name = "role_id")
+ )
+ private Collection roles;
+
+
+ public UserEntity(){}
+
+ public UserEntity(String userName, String password, String email) {
+ this.userName = userName;
+ this.password = password;
+ this.email = email;
+ }
+
+ public int getId() {
+ return id;
+ }
+ public String getUserName() {
+ return userName;
+ }
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+ public String getPassword() {
+ return password;
+ }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ public Collection getRoles() {
+ return roles;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public void setARole(Role role){
+ if(this.roles == null){
+ this.roles = new HashSet();
+ }
+
+ this.roles.add(role);
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenGeneratorFilter.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenGeneratorFilter.java
new file mode 100644
index 0000000..4af13bf
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenGeneratorFilter.java
@@ -0,0 +1,81 @@
+package com.example.cezenPBX.security;
+
+import com.example.cezenPBX.constents.SecurityConstants;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.crypto.SecretKey;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+public class JWTTokenGeneratorFilter extends OncePerRequestFilter {
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+ //at this point the user is authenticated we just have to send the token back
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (null != authentication) {
+
+ //get the JWT key from the contents we defined
+ // Keys, Jwts class comes from pom.xml
+ SecretKey key = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
+
+ //creating a JWT token
+ // issuer issues a jwt token
+ //subject can be any value
+ String jwt = Jwts.builder().issuer("Mathew Francis").subject("JWT_Token")
+ //building the token
+ .claim("username", authentication.getName())
+ .claim("authorities", populateAuthorities(authentication.getAuthorities()))
+ .issuedAt(new Date())
+ .expiration(new Date((new Date()).getTime() + 30000000))
+ //signing it with the key we set on line 35
+ .signWith(key).compact();
+ //SecurityConstants.JWT_HEADER, in the Constants SecurityConstants folder
+ //response.setHeader(SecurityConstants.JWT_HEADER, jwt);
+ //uncomment for cookie based saving
+ Cookie cookie = new Cookie(SecurityConstants.JWT_HEADER,jwt);
+ cookie.setHttpOnly(true);
+ cookie.setSecure(true);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ System.out.println("JWT Generated");
+ }
+ System.out.println("Intercepted");
+
+ System.out.println(response.getHeader("X-XSRF-TOKEN"));
+ filterChain.doFilter(request, response);
+ }
+
+ //only generate if the path is login
+ //other words this method will return false for /login
+ @Override
+ protected boolean shouldNotFilter(HttpServletRequest request) {
+
+ return !request.getServletPath().equals("/open/login");
+ //return !(request.getServletPath().equals("/open/signup") || request.getServletPath().equals("/open/login"));
+ }
+
+ // gets the authority's from granted authority which we set in the configuration CustomAuthenticationProvider class
+ // plug in user auth into jwt token
+ private String populateAuthorities(Collection extends GrantedAuthority> collection) {
+ Set authoritiesSet = new HashSet<>();
+ for (GrantedAuthority authority : collection) {
+ authoritiesSet.add(authority.getAuthority());
+ }
+ return String.join(",", authoritiesSet);
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenValidatorFilter.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenValidatorFilter.java
new file mode 100644
index 0000000..9390541
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/security/JWTTokenValidatorFilter.java
@@ -0,0 +1,81 @@
+package com.example.cezenPBX.security;
+
+import com.example.cezenPBX.constents.SecurityConstants;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.crypto.SecretKey;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class JWTTokenValidatorFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+
+ // SecurityConstants
+ // public static final String JWT_KEY = "jxgEQeXHuPq8VdbyYFNkANdudQ53YUn4";
+ // public static final String JWT_HEADER = "Authorization";
+ //String jwt = request.getHeader(SecurityConstants.JWT_HEADER);
+ //below is the COOKIE approach
+ String jwt = null;
+ for(var cookie : request.getCookies()){
+ if(cookie.getName().equals("Authorization")){
+ System.out.print("COOKIE");
+ System.out.println(cookie.getValue());
+ jwt = cookie.getValue();
+ }
+ }
+ if (null != jwt) {
+ try {
+ //generating the key
+ SecretKey key = Keys.hmacShaKeyFor(
+ SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
+
+ //verification of legitimacy
+ Claims claims = Jwts.parser()
+ .verifyWith(key)
+ .build()
+ .parseSignedClaims(jwt)
+ .getPayload();
+ String username = String.valueOf(claims.get("username"));
+ String authorities = (String) claims.get("authorities");
+
+// System.out.println("JWT name : "+ username);
+// System.out.println("JWT auth "+ authorities);
+
+ //if successful the result will be stored in SecurityContextHolder
+ Authentication auth = new UsernamePasswordAuthenticationToken(username, null,
+ //this comes in a string of comas and values
+ AuthorityUtils.commaSeparatedStringToAuthorityList(authorities));
+ SecurityContextHolder.getContext().setAuthentication(auth);
+ } catch (Exception e) {
+ throw new BadCredentialsException("Invalid Token received!");
+ }
+
+ }
+ filterChain.doFilter(request, response);
+ }
+
+ //should be executed for all the api except the login api
+ @Override
+ protected boolean shouldNotFilter(HttpServletRequest request) {
+
+ return request.getServletPath().equals("/open/signup")
+ || request.getServletPath().equals("/open/login");
+// //bellow was done to archive this /exposed/**
+// request.getServletPath().split("/")[1].equals("exposed");
+ }
+}
diff --git a/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/service/PbxUserService.java b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/service/PbxUserService.java
new file mode 100644
index 0000000..7534b1d
--- /dev/null
+++ b/MySQL_conf_pbx/test1/springCezenPBX/src/main/java/com/example/cezenPBX/service/PbxUserService.java
@@ -0,0 +1,35 @@
+package com.example.cezenPBX.service;
+
+import com.example.cezenPBX.DAO.UserOpsDAO;
+import com.example.cezenPBX.DTO.ReturnStatus;
+import com.example.cezenPBX.entity.user.UserEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class PbxUserService {
+
+ @Autowired
+ private UserOpsDAO userOpsDAO;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+
+ // must perform the sanity checks before being set to the database
+ // method will return a faulty return status if the damin exists
+ public ReturnStatus adminSetUserNamePasswordSet(String userName, String password, String confirmPassword, String email){
+ // password will be checked here
+ if(!password.equals(confirmPassword)){
+ return new ReturnStatus(false, "Passwords do not match", "Passwords do not match");
+ }
+ // password encryption
+ UserEntity userEntity = new UserEntity(userName, passwordEncoder.encode(password), email);
+
+ // commit the username and password to the database
+ return userOpsDAO.adminSetUsernameAndPassword(userEntity);
+ }
+}