diff --git a/plugins/de.cognicrypt.codegenerator.tests/src/de/cognicrypt/codegenerator/generator/test/UserAuthManagerCodeGenTest.java b/plugins/de.cognicrypt.codegenerator.tests/src/de/cognicrypt/codegenerator/generator/test/UserAuthManagerCodeGenTest.java new file mode 100644 index 000000000..d6d6b633b --- /dev/null +++ b/plugins/de.cognicrypt.codegenerator.tests/src/de/cognicrypt/codegenerator/generator/test/UserAuthManagerCodeGenTest.java @@ -0,0 +1,91 @@ +package de.cognicrypt.codegenerator.generator.test; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.logging.Logger; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import de.cognicrypt.codegenerator.generator.CodeGenerator; +import de.cognicrypt.codegenerator.generator.CrySLBasedCodeGenerator; +import de.cognicrypt.codegenerator.tasks.Task; +import de.cognicrypt.codegenerator.testutilities.TestUtils; +import de.cognicrypt.codegenerator.wizard.Configuration; +import de.cognicrypt.utils.DeveloperProject; + +/** + * @author Shahrzad Asghari + */ +public class UserAuthManagerCodeGenTest { + private Logger log = Logger.getLogger(UserAuthManagerCodeGenTest.class.getName()); + private IJavaProject testJavaProject; + private CodeGenerator generatorAuthManager; + private Task authManagerTask; + private Configuration configAuthManager; + private DeveloperProject developerProject; + private IResource targetFile; + private ICompilationUnit testClassUnit; +// private String taskName = "UserAuthorityManager"; + Task taskName = TestUtils.getTask("UserAuthorityManager"); + + @After + public void tearDown() throws CoreException { + TestUtils.deleteProject(this.testJavaProject.getProject()); + } + + @Before + public void setUp() throws Exception { + this.testJavaProject = TestUtils.createJavaProject(CodeGenTestConstants.PROJECT_NAME); + targetFile = TestUtils.generateJavaClassInJavaProject(this.testJavaProject, CodeGenTestConstants.PACKAGE_NAME, + CodeGenTestConstants.CLASS_NAME); + this.authManagerTask = TestUtils.getTask("UserAuthorityManager"); + this.generatorAuthManager = new CrySLBasedCodeGenerator(targetFile); + this.developerProject = this.generatorAuthManager.getDeveloperProject(); + this.testClassUnit = TestUtils.getICompilationUnit(this.developerProject, CodeGenTestConstants.PACKAGE_NAME, + CodeGenTestConstants.JAVA_CLASS_NAME); + TestUtils.openJavaFileInWorkspace(this.developerProject, "testPackage", this.testClassUnit); + + } + + /** + * Scenario: User chooses User Authentication manager task and on the first pages + * chooses the second answer to generate user authentication service. + * + * @throws CoreException. + * @throws IOException this exception happens if an I/O error appears while creating and copying a file in createCrySLConfiguration. + * @throws CoreException this exceptions happens when the project does not exist or is not open. + */ + @Test + public void testCodeGenerationUserAuthentication() throws IOException, CoreException { + this.configAuthManager = TestUtils.createCrySLConfiguration("userauthoritymanagerauth", testClassUnit.getResource(), + generatorAuthManager, this.developerProject, taskName); + final boolean encCheck = this.generatorAuthManager.generateCodeTemplates(this.configAuthManager, + this.authManagerTask.getAdditionalResources()); + + assertTrue(encCheck); + } + + /** + * Scenario: User chooses User Authentication manager task and on the first pages + * chooses the first answer to generate a password generator service. + * + * @throws CoreException this exceptions happens when the project does not exist or is not open. + * @throws IOException this exception happens if an I/O error appears while creating and copying a file in createCrySLConfiguration. + */ + @Test + public void testCodeGenerationPassGenerator() throws CoreException, IOException { + this.configAuthManager = TestUtils.createCrySLConfiguration("userauthoritymanagerpassgen", testClassUnit.getResource(), + generatorAuthManager, this.developerProject, taskName); + final boolean encCheck = this.generatorAuthManager.generateCodeTemplates(this.configAuthManager, + this.authManagerTask.getAdditionalResources()); + + assertTrue(encCheck); + } +} \ No newline at end of file diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/CrySLCodeGenerator.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/CrySLCodeGenerator.java index 91bf18fec..414b9f2cf 100644 --- a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/CrySLCodeGenerator.java +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/CrySLCodeGenerator.java @@ -16,6 +16,7 @@ public class CrySLCodeGenerator implements RuleContext, BeforeRuleContext { private RuleGenConfig last = null; private List ruleConfigs; + private String customMain; private CrySLCodeGenerator() {} @@ -45,4 +46,8 @@ private void resolveLast() { last = null; } } + public CrySLCodeGenerator setCustomMain(String customMain) { + this.customMain = customMain; + return this; + } } diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/RuleContext.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/RuleContext.java index 2be955154..fb2356ed4 100644 --- a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/RuleContext.java +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/RuleContext.java @@ -17,4 +17,6 @@ public interface RuleContext { public RuleContext includeClass(String rule); public boolean generate(); + + public CrySLCodeGenerator setCustomMain(String string); } diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerauth/UserAuthentication.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerauth/UserAuthentication.java new file mode 100644 index 000000000..c57e70cc9 --- /dev/null +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerauth/UserAuthentication.java @@ -0,0 +1,87 @@ +/******************************************************************************** + * Copyright (c) 2015-2021 TU Darmstadt, Paderborn University + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package de.cognicrypt.codegenerator.crysl.templates.userauthoritymanagerauth; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Base64; + +import de.cognicrypt.codegenerator.crysl.CrySLCodeGenerator; + +/** + * The Class UserAuthentication verifies the users input, the username and password. + */ +public class UserAuthentication { + //hash and salt will be stored as string + /** + * Takes username and password as inputs to verifies the password. Connects to the MySQL database + * and retrieves the hashed password and salt for the desired username and makes a new hash from the input password + * with the same salt, then checks the equality of the hash in the database and the new hash. If the username does not + * exist in the database, it throws an exception. Users may modify the database's username, password, URL and tableName to their own. + * Usernames and Passwords are all considered to be unique. + * note: SQL must be installed. + * + * @param username the input username to be searched in the database. + * @param pwd the input password for that username, the correction of this password will be checked by this method. + * @return true, if the username exists and the input password is correct. + * @throws Exception This exception is thrown if the username does not exist in the database. + * @throws ClassNotFoundException This exception is thrown if MySQL jar file is not in the buildpath. It contains the class "com.mysql.cj.jdbc.Driver". + * @throws GeneralSecurityException This exception is thrown if a security-related exception happens that extends this general exception. + * @throws InvalidKeySpecException This exception is thrown when key specifications are invalid. + */ + //for this to work, sql must be installed and put in env path + public static boolean userAuth(String username, char[] pwd) throws Exception { + String databaseUsername = "root"; + String databasePassword = "test"; + String databaseURL = "jdbc:mysql://localhost:3306/myDatabase"; + String tableName = " mytb "; + + Boolean result = false; + + String salt = "" ; + String hash = ""; + + int iterationCount = 65536; + int keysize = 128; + + byte[] hashedPwd = null; + + Class.forName("com.mysql.cj.jdbc.Driver"); + + Connection connection = DriverManager.getConnection(databaseURL, databaseUsername, databasePassword); + + Statement stmt = connection.createStatement(); + String SQL = "SELECT * FROM" + tableName + "WHERE USERNAME='" + username + "'"; + ResultSet queryResult = stmt.executeQuery(SQL); + if (queryResult.isBeforeFirst()) { + while (queryResult.next()) { + salt = queryResult.getString("salt"); + hash = queryResult.getString("hash"); + } + }else { + throw new Exception("User not found"); + } + + byte [] bytedSalt = Base64.getDecoder().decode(salt); + + CrySLCodeGenerator.getInstance().includeClass("javax.crypto.spec.PBEKeySpec") + .addParameter(pwd, "password").addParameter(keysize, "keylength").addParameter(iterationCount, "iterationCount") + .addParameter(bytedSalt, "salt").includeClass("javax.crypto.SecretKeyFactory").includeClass("javax.crypto.SecretKey") + .addParameter(hashedPwd, "this").generate(); + + String hashedPwdString = Base64.getEncoder().encodeToString(hashedPwd); + + if (hash.equals(hashedPwdString)) { + result = true;} + return result; + } +} \ No newline at end of file diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerpassgen/PassGenerator.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerpassgen/PassGenerator.java new file mode 100644 index 000000000..f9e44bcac --- /dev/null +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/crysl/templates/userauthoritymanagerpassgen/PassGenerator.java @@ -0,0 +1,79 @@ +/******************************************************************************** + * Copyright (c) 2015-2021 TU Darmstadt, Paderborn University + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package de.cognicrypt.codegenerator.crysl.templates.userauthoritymanagerpassgen; + +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +import de.cognicrypt.codegenerator.crysl.CrySLCodeGenerator; + +/** + * The Class PassGenerator generates a secure password that meets all requirements + * for a standard password described in NIST (National Institute of Standards and Technology). + */ + +public class PassGenerator { + + /** + * Generates a secure random password of length 12. This password consists of numbers, symbols, uppercase and lowercase + * letters that are randomly distributed in the password. The length of the password must be equal to or more than 4, cause it must include + * one of each set of characters. + * + * @return the password. + * @throws GeneralSecurityException This exception is thrown if a security-related exception happens that extends this general exception. + * @throws NoSuchAlgorithmException This exception is thrown if no Provider supports a SecureRandomSpi implementation for the specified algorithm. {@link #generateRandomCharacter(String) generateRandomCharacter} + */ + public static String generateRandomPassword() throws NoSuchAlgorithmException, GeneralSecurityException + { + int length = 12; + final String capitalAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + final String smallAlphabet = "abcdefghijklmnopqrstuvwxyz"; + final String numbers = "0123456789"; + //removed dot slashes and quotations- library + final String specialChars = "~!@#$%^&*()-_=+[{]};:,<>?"; + final String allCases = capitalAlphabet + smallAlphabet + numbers + specialChars; + + List password = new ArrayList(); + + password.add(generateRandomCharacter(capitalAlphabet)); + password.add(generateRandomCharacter(smallAlphabet)); + password.add(generateRandomCharacter(numbers)); + password.add(generateRandomCharacter(specialChars)); + + for (int i = 4; i < length; i++) { + password.add(generateRandomCharacter(allCases)); + } + // relocate each character in password + Collections.shuffle(password); + return String.join("", password); + } + + /** + * Generates a random integer (randIndex) in range of length of characters (e.g. 10 in numbers) + * and returns the randIndex'th item of the list of characters. + * + * @param chars the character, e.g., upper case letters. + * @return the string one character from the character set that is randomly selected. + * @throws GeneralSecurityException This exception is thrown if a security-related exception happens that extends this general exception. + * @throws NoSuchAlgorithmException This exception is thrown if no Provider supports a SecureRandomSpi implementation for the specified algorithm. + */ + public static String generateRandomCharacter(String chars) throws NoSuchAlgorithmException, GeneralSecurityException{ + + int length = chars.length(); + int randIndex = 0; + CrySLCodeGenerator.getInstance().includeClass("java.security.SecureRandom").addParameter(length, "range").addParameter(randIndex, "randIntInRange").setCustomMain("generateRandomPassword").generate(); + return String.valueOf(chars.charAt(randIndex)); + } + +} \ No newline at end of file diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/CrySLBasedCodeGenerator.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/CrySLBasedCodeGenerator.java index a8f71b874..0f70a2fe6 100644 --- a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/CrySLBasedCodeGenerator.java +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/CrySLBasedCodeGenerator.java @@ -429,10 +429,14 @@ private void generateTemplateUsageBody(Set generatedClasses, Gen List> declaredVariables = new ArrayList<>(); declaredVariables.addAll(tmplUsage.getParameters()); + //check if there is a custom main method in the class for (GeneratorMethod gen : generatedClass.getMethods()) { - if (gen.getRules().isEmpty()) { - continue; + if (generatedClass.getCustomMain() != null) { + if (!gen.getName().equals(generatedClass.getCustomMain())) { + continue; + } } + else if (gen.getRules().isEmpty()) {continue;} tmplUsage.addExceptions(gen.getExceptions()); String returnType = gen.getReturnType(); @@ -1324,6 +1328,9 @@ public boolean visit(MethodInvocation node) { methLims.put(1, node.getStartPosition() + node.getLength()); } else if ("getInstance".equals(calledMethodName)) { methLims.put(0, node.getStartPosition() - "CrySLCodeGenerator.".length()); + }else if ("setCustomMain".equals(calledMethodName)) { + String cMain = Utils.filterQuotes(arguments.get(0).toString()); + templateClass.setCustomMain(cMain); } return super.visit(node); } diff --git a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/GeneratorClass.java b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/GeneratorClass.java index 5398a5378..29d4eb51f 100644 --- a/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/GeneratorClass.java +++ b/plugins/de.cognicrypt.codegenerator/src/main/java/de/cognicrypt/codegenerator/generator/GeneratorClass.java @@ -24,9 +24,11 @@ public class GeneratorClass { private String modifier; private String className; private List methods; - private File associatedFile; + private File associatedFile; + private String customMain; private String header = ""; private String classJavaDoc = ""; + public GeneratorClass() { imports = new HashSet(); @@ -138,5 +140,13 @@ public String toString() { classContent.append("}"); return classContent.toString(); } + public void setCustomMain(String cMain) { + this.customMain = cMain; + + } + + public String getCustomMain() { + return this.customMain; + } } diff --git a/plugins/de.cognicrypt.codegenerator/src/main/resources/TaskDesc/UserAuthorityManager.json b/plugins/de.cognicrypt.codegenerator/src/main/resources/TaskDesc/UserAuthorityManager.json new file mode 100644 index 000000000..4455bd9e1 --- /dev/null +++ b/plugins/de.cognicrypt.codegenerator/src/main/resources/TaskDesc/UserAuthorityManager.json @@ -0,0 +1,19 @@ +[{ + "id": "0", + "content": [{ + "id": "0", + "element": "radio", + "questionText": "Which of the following tasks do you wish to generate?", + "answers": [ { + "value": "A secure random password generator", + "option": "passgen", + "defaultAnswer": true + }, + { + "value": "User Authentication service that checks user's username and password from SQL database", + "option": "auth", + "nextID": "-1" + }] + }], + "nextID": "-1" + }] \ No newline at end of file diff --git a/plugins/de.cognicrypt.codegenerator/src/main/resources/Tasks/tasks.json b/plugins/de.cognicrypt.codegenerator/src/main/resources/Tasks/tasks.json index 8a12df622..3324a5b7f 100644 --- a/plugins/de.cognicrypt.codegenerator/src/main/resources/Tasks/tasks.json +++ b/plugins/de.cognicrypt.codegenerator/src/main/resources/Tasks/tasks.json @@ -39,6 +39,14 @@ "codeGen": "XSL", "isSelected": false }, + { + "name": "UserAuthorityManager", + "description": "User authorization and secure password generator", + "taskDescription": "Cognicrypt provides a secure username and password and verifies the validity of a given username and password in this usecase.", + "image": "authManager", + "codeGen": "CrySL", + "isSelected": false + }, { "name": "TestCryslTask", "description": "TestCryslTask", diff --git a/plugins/de.cognicrypt.codegenerator/src/main/resources/images/authManager.png b/plugins/de.cognicrypt.codegenerator/src/main/resources/images/authManager.png new file mode 100644 index 000000000..b2b92473b Binary files /dev/null and b/plugins/de.cognicrypt.codegenerator/src/main/resources/images/authManager.png differ