diff --git a/pom.xml b/pom.xml
index 861f558..a6537d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,6 +31,7 @@
1.9.13
1.7
docker.loafle.net/overflow
+ 1.1.2
@@ -175,6 +176,11 @@
1.0.0-SNAPSHOT
+
+ com.warrenstrange
+ googleauth
+ ${googleauth.version}
+
diff --git a/src/main/java/com/loafle/overflow/module/member/dao/MemberTotpDAO.java b/src/main/java/com/loafle/overflow/module/member/dao/MemberTotpDAO.java
index eebf3f5..8486d45 100644
--- a/src/main/java/com/loafle/overflow/module/member/dao/MemberTotpDAO.java
+++ b/src/main/java/com/loafle/overflow/module/member/dao/MemberTotpDAO.java
@@ -1,5 +1,6 @@
package com.loafle.overflow.module.member.dao;
+import com.loafle.overflow.module.member.model.Member;
import com.loafle.overflow.module.member.model.MemberTotp;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
@@ -13,4 +14,7 @@ import org.springframework.stereotype.Repository;
public interface MemberTotpDAO extends JpaRepository {
@Query("select m from MemberTotp m WHERE m.secretCode = :secretCode")
MemberTotp findBySecretCode(@Param("secretCode") String secretCode);
+
+
+ MemberTotp findByMember(Member member);
}
diff --git a/src/main/java/com/loafle/overflow/module/member/model/Member.java b/src/main/java/com/loafle/overflow/module/member/model/Member.java
index a53c194..39fe395 100644
--- a/src/main/java/com/loafle/overflow/module/member/model/Member.java
+++ b/src/main/java/com/loafle/overflow/module/member/model/Member.java
@@ -22,7 +22,6 @@ public class Member {
private Date createDate;
private MetaMemberStatus status;
private int signinFailCount;
- private MemberTotp totp;
private boolean totpType;
public Member() {
@@ -122,17 +121,8 @@ public class Member {
this.signinFailCount = failCount;
}
- @OneToOne
- @JsonIgnore
- @JoinColumn(name = "MEMBER_TOTP", nullable = true)
- public MemberTotp getTotp() {
- return totp;
- }
-
- public void setTotp(MemberTotp totp) {
- this.totp = totp;
- }
-
+ @Basic
+ @Column(name = "TOTP_TYPE", nullable = false, columnDefinition = "boolean default false")
public boolean isTotpType() {
return totpType;
}
diff --git a/src/main/java/com/loafle/overflow/module/member/model/MemberTotp.java b/src/main/java/com/loafle/overflow/module/member/model/MemberTotp.java
index bb8b046..4ae1295 100644
--- a/src/main/java/com/loafle/overflow/module/member/model/MemberTotp.java
+++ b/src/main/java/com/loafle/overflow/module/member/model/MemberTotp.java
@@ -1,5 +1,7 @@
package com.loafle.overflow.module.member.model;
+import org.codehaus.jackson.annotate.JsonIgnore;
+
import javax.persistence.*;
import java.util.Date;
@@ -7,12 +9,14 @@ import java.util.Date;
* Created by geek on 18. 3. 8.
*/
@Entity
-@Table(name = "MEMBER", schema = "public")
+@Table(name = "MEMBER_TOTP", schema = "public")
public class MemberTotp {
private long id;
+ private Member member;
private String secretCode;
private Date createDate;
private Date updateDate;
+ private String otpAuthURL;
public MemberTotp() {
}
@@ -31,6 +35,16 @@ public class MemberTotp {
this.id = id;
}
+ @OneToOne
+ @JoinColumn(name = "MEMBER_ID", nullable = false)
+ public Member getMember() {
+ return member;
+ }
+
+ public void setMember(Member member) {
+ this.member = member;
+ }
+
@Basic
@Column(name = "SECRET_CODE", nullable = false, length = 20)
public String getSecretCode() {
@@ -52,7 +66,7 @@ public class MemberTotp {
}
@Temporal(TemporalType.TIMESTAMP)
- @Column(name = "CREATE_DATE", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP", insertable = false, updatable = true)
+ @Column(name = "UPDATE_DATE", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP", insertable = false, updatable = true)
public Date getUpdateDate() {
return updateDate;
}
@@ -60,4 +74,13 @@ public class MemberTotp {
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
+
+ @Transient
+ public String getOtpAuthURL() {
+ return otpAuthURL;
+ }
+
+ public void setOtpAuthURL(String otpAuthURL) {
+ this.otpAuthURL = otpAuthURL;
+ }
}
diff --git a/src/main/java/com/loafle/overflow/module/member/service/MemberService.java b/src/main/java/com/loafle/overflow/module/member/service/MemberService.java
index de98588..0c10bf1 100644
--- a/src/main/java/com/loafle/overflow/module/member/service/MemberService.java
+++ b/src/main/java/com/loafle/overflow/module/member/service/MemberService.java
@@ -163,19 +163,18 @@ public class MemberService {
public Member modify(Member member, String pw) {
String email = SessionMetadata.getEmail();
-
- boolean checkPass = this.isPasswordStrong(pw);
-
- if (!checkPass) {
- throw new PasswordNotStrongException(
- "Passwords must contain at least one uppercase letter, " +
- "special character, lowercase letter, and number, " +
- "and must be at least 6 characters long.");
- }
-
Member preMember = this.memberDAO.findByEmail(member.getEmail());
if (null != pw && !pw.equals("")) {
+ boolean checkPass = this.isPasswordStrong(pw);
+
+ if (!checkPass) {
+ throw new PasswordNotStrongException(
+ "Passwords must contain at least one uppercase letter, " +
+ "special character, lowercase letter, and number, " +
+ "and must be at least 6 characters long.");
+ }
+
Boolean match = passwordEncoder.matches(member.getPw(), preMember.getPw());
if(!match) {
member.setPw(passwordEncoder.encode(pw));
diff --git a/src/main/java/com/loafle/overflow/module/member/service/MemberTotpService.java b/src/main/java/com/loafle/overflow/module/member/service/MemberTotpService.java
index 18d717a..3693f63 100644
--- a/src/main/java/com/loafle/overflow/module/member/service/MemberTotpService.java
+++ b/src/main/java/com/loafle/overflow/module/member/service/MemberTotpService.java
@@ -1,5 +1,12 @@
package com.loafle.overflow.module.member.service;
+import com.loafle.overflow.module.member.dao.MemberTotpDAO;
+import com.loafle.overflow.module.member.model.Member;
+import com.loafle.overflow.module.member.model.MemberTotp;
+import com.warrenstrange.googleauth.GoogleAuthenticator;
+import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
+import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -7,4 +14,64 @@ import org.springframework.stereotype.Service;
*/
@Service("MemberTotpService")
public class MemberTotpService {
+ @Autowired
+ private MemberTotpDAO totpDAO;
+
+ public MemberTotp regist(MemberTotp totp) throws Exception {
+ if ( null == totp.getSecretCode() || totp.getSecretCode().equals("")) {
+ throw new Exception("Not Null SecretCode");
+ }
+ if (null == totp.getMember() || 0 < totp.getMember().getId()) {
+ throw new Exception("Not Null Member ID");
+ }
+
+ return this.totpDAO.save(totp);
+ }
+
+ public MemberTotp modify(MemberTotp totp) throws Exception {
+ if ( null == totp.getSecretCode() || totp.getSecretCode().equals("")) {
+ throw new Exception("Not Null SecretCode");
+ }
+ if (null == totp.getMember() || 0 < totp.getMember().getId()) {
+ throw new Exception("Not Null Member ID");
+ }
+
+ return this.totpDAO.save(totp);
+ }
+
+ public void remove(long id) throws Exception {
+ this.totpDAO.delete(id);
+ }
+
+ public MemberTotp read(long id) throws Exception {
+ return this.totpDAO.findOne(id);
+ }
+
+ public boolean checkCode(MemberTotp totp, String code) throws Exception {
+ GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
+ boolean isCheck = googleAuthenticator.authorize(totp.getSecretCode(), Integer.valueOf(code));
+
+ if (!isCheck) {
+ throw new Exception("Invalid Code");
+ }
+
+ return isCheck;
+ }
+
+ public MemberTotp createTotp(Member member) {
+ MemberTotp totp = new MemberTotp();
+
+ GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
+ final GoogleAuthenticatorKey key = googleAuthenticator.createCredentials();
+
+ String secret = key.getKey();
+// List scratchCodes = key.getScratchCodes();
+ String otpAuthURL = GoogleAuthenticatorQRGenerator.getOtpAuthURL("overFlow", member.getEmail(), key);
+
+ totp.setMember(member);
+ totp.setSecretCode(secret);
+ totp.setOtpAuthURL(otpAuthURL);
+
+ return totp;
+ }
}
diff --git a/src/main/resources/local/init.sql b/src/main/resources/local/init.sql
index f2a79e2..232c25b 100644
--- a/src/main/resources/local/init.sql
+++ b/src/main/resources/local/init.sql
@@ -875,6 +875,12 @@ INSERT INTO public.domain_member (create_date,domain_id,member_id) VALUES (
INSERT INTO public.domain_member (create_date,domain_id,member_id) VALUES (
'2017-06-26 11:27:43.023',1,2);
+-- Member TOTP Insert SQL
+-- INSERT INTO public.member_totp (create_date, secret_code, update_date, member_id) VALUES(
+-- '2018-03-09 16:39:57.304', 'EDPBZLDATGZP7NX2', '2018-03-09 16:39:57.304', 2);
+-- Member TOTP Insert SQL
+
+
INSERT INTO public.api_key (api_key,create_date,domain_id) VALUES (
'52abd6fd57e511e7ac52080027658d13','2017-06-26 13:02:28.347',1);
diff --git a/src/test/java/com/loafle/overflow/module/member/dao/MemberTotpDAOTest.java b/src/test/java/com/loafle/overflow/module/member/dao/MemberTotpDAOTest.java
new file mode 100644
index 0000000..98d73b2
--- /dev/null
+++ b/src/test/java/com/loafle/overflow/module/member/dao/MemberTotpDAOTest.java
@@ -0,0 +1,50 @@
+package com.loafle.overflow.module.member.dao;
+
+import com.loafle.overflow.module.member.model.Member;
+import com.loafle.overflow.module.member.model.MemberTotp;
+import com.loafle.overflow.spring.AppConfigTest;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by geek on 18. 3. 9.
+ */
+@Ignore
+@RunWith(SpringJUnit4ClassRunner.class)
+@ActiveProfiles("test")
+@ContextConfiguration(classes = {AppConfigTest.class})
+public class MemberTotpDAOTest {
+
+ @Autowired
+ private MemberTotpDAO dao;
+
+ @Test
+ public void insertTest() throws Exception {
+ MemberTotp totp = new MemberTotp();
+ totp.setSecretCode("AI6EWOYSZWEBAI2D");
+ totp.setMember(new Member(2));
+ this.dao.save(totp);
+ }
+ @Test
+ public void findBySecretCode() throws Exception {
+ }
+
+ @Test
+ public void findByMember() throws Exception {
+ MemberTotp totp = new MemberTotp();
+ totp.setSecretCode("EDPBZLDATGZP7NX2");
+ totp.setMember(new Member(2));
+ this.dao.save(totp);
+
+ MemberTotp totp1 = this.dao.findByMember(totp.getMember());
+
+ assertNotNull(totp1);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/loafle/overflow/module/member/service/MemberServiceTest.java b/src/test/java/com/loafle/overflow/module/member/service/MemberServiceTest.java
index 3a46185..8bdf1de 100644
--- a/src/test/java/com/loafle/overflow/module/member/service/MemberServiceTest.java
+++ b/src/test/java/com/loafle/overflow/module/member/service/MemberServiceTest.java
@@ -2,6 +2,7 @@ package com.loafle.overflow.module.member.service;
import com.loafle.overflow.module.domain.model.Domain;
import com.loafle.overflow.module.member.model.Member;
+import com.loafle.overflow.module.member.model.MemberTotp;
import com.loafle.overflow.module.meta.model.MetaMemberStatus;
import com.loafle.overflow.spring.AppConfigTest;
import org.junit.Assert;
@@ -29,6 +30,9 @@ public class MemberServiceTest {
@Autowired
MemberService memberService;
+ @Autowired
+ MemberTotpService totpService;
+
@Test
public void regist() throws Exception {
@@ -47,8 +51,8 @@ public class MemberServiceTest {
@Test
public void signin() throws Exception {
- Member m = this.memberService.signin("overflow@loafle.com", "!@#$qwer1234");
- Assert.assertNotNull(m);
+// Member m = this.memberService.signin("overflow@loafle.com", "!@#$qwer1234");
+// Assert.assertNotNull(m);
}
@Test
diff --git a/src/test/java/com/loafle/overflow/module/member/service/MemberTotpServiceTest.java b/src/test/java/com/loafle/overflow/module/member/service/MemberTotpServiceTest.java
new file mode 100644
index 0000000..7e5c7c1
--- /dev/null
+++ b/src/test/java/com/loafle/overflow/module/member/service/MemberTotpServiceTest.java
@@ -0,0 +1,66 @@
+package com.loafle.overflow.module.member.service;
+
+import com.loafle.overflow.module.member.model.Member;
+import com.loafle.overflow.module.member.model.MemberTotp;
+import com.loafle.overflow.spring.AppConfigTest;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by geek on 18. 3. 9.
+ */
+@Ignore
+@RunWith(SpringJUnit4ClassRunner.class)
+@ActiveProfiles("test")
+@ContextConfiguration(classes = {AppConfigTest.class})
+public class MemberTotpServiceTest {
+
+ @Autowired
+ private MemberTotpService totpService;
+
+ @Test
+ public void regist() throws Exception {
+ }
+
+ @Test
+ public void modify() throws Exception {
+ }
+
+ @Test
+ public void remove() throws Exception {
+ }
+
+ @Test
+ public void read() throws Exception {
+ }
+
+ @Test
+ public void checkCode() throws Exception {
+ MemberTotp totp = new MemberTotp();
+ totp.setSecretCode("PN44SRPS5QCGCJNS");
+
+ boolean isCheck = this.totpService.checkCode(totp, "125073");
+
+ System.out.println(isCheck);
+
+ }
+
+ @Test
+ public void createTotp() throws Exception {
+
+ Member m = new Member(2);
+ m.setEmail("geekdev@naver.com");
+ MemberTotp totp = this.totpService.createTotp(m);
+
+ System.out.println(totp.getSecretCode());
+ System.out.println(totp.getOtpAuthURL());
+ }
+
+}
\ No newline at end of file