From 2e5d8d316a1993690c98854d5b866a15c799e121 Mon Sep 17 00:00:00 2001 From: GME Date: Sun, 21 Oct 2018 19:09:29 +0200 Subject: [PATCH] EnrollAdmin Test succeed to enroll existing default admin from blockchain. --- msp/Org1/admin.context | Bin 0 -> 1697 bytes .../blockchain/client/CAClientWrapper.java | 37 ++++++++++++---- .../java/blockchain/configuration/Config.java | 28 ++++++++++++ src/main/java/blockchain/utility/Util.java | 2 + .../blockchain/client/TestEnrollAdmin.java | 40 ++++++++++++++++++ .../blockchain/client/CAClientWrapper.class | Bin 2284 -> 3569 bytes .../blockchain/configuration/Config.class | Bin 0 -> 886 bytes target/classes/blockchain/utility/Util.class | Bin 3748 -> 3819 bytes .../blockchain/client/TestEnrollAdmin.class | Bin 0 -> 2371 bytes 9 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 msp/Org1/admin.context create mode 100644 src/main/java/blockchain/configuration/Config.java create mode 100644 src/test/java/blockchain/client/TestEnrollAdmin.java create mode 100644 target/classes/blockchain/configuration/Config.class create mode 100644 target/test-classes/blockchain/client/TestEnrollAdmin.class diff --git a/msp/Org1/admin.context b/msp/Org1/admin.context new file mode 100644 index 0000000000000000000000000000000000000000..4e2b42eec80f7c1d93c6abada60613ec82570c41 GIT binary patch literal 1697 zcmb_cOQ_sb7(RFItBp#vr4+S`DpIv$Gc)PTee_|QlVmcvlgyn*X6DXRkW40%_au|Y zO>&V+U0AFOkz$1lVx=w=DuRfMF1pc$AT6lXO;KFvMy#8vsae*V{Y z&d2}#mu`Y-*8z|A3`^8SMNo&R?@A8Zj4#3(dQ#|tjWdw~Gc1@DMA7nxo(Fcany@Nl z3}Gl|8lIyLXc~L-PB(zi{@GZ32i{bCbPpcPFAjN_yQF6RZs7YOlJg{d2$dyFjQN1Wr zmZGYlIx(P^`sQGAAVo8keFRnKnIc2rJT>+r9K*mljUezYE#mF_MG?(KS7;X$u3if$xkI*UwK75l9wV(lLo`F9OZN>?qpBR99XBLGj;@@>R_SWZ5Og!Egz8hCQ{H+x^&L&X|T&dj)u{QZgBZUT&8G(*su{i zph|d_!675*X&4CwZoX|86|x|%*5w8x^Ey#l9$`_in761v^Q(Rs8cjdFNEBF4Cj=~2SC*@ij!aCjY@~w1k{t&_Dbd0d`bEXyw7uGVTKE>}u82`OBKOfJVakvZ3GE%mC( zpvz7+KIyavk$c&8hm^0618v1-iSt(#zcF=Y6dW0c;SmKMk zwV-PnQ>^!!!v*meG9FT@LjHYlV*%|>#EssWd31B;-<-Vv@K;xNo*OF#u^n|)@T55A zfk*BUN%d|l*7A1S?-{B%PJH;@#5T5*)}#NCuXOj zY>=9mnA-Q@%@1_kX^Bdv5*g?t@DoAD=w+3S?j0djZ)hdWW2ZVCu}f zxA(69cM1M+sLC`pNxJOv}k^=N~Eg WU;gHS*<^upjj9Kxg}$i{?LPrOtvA8| literal 0 HcmV?d00001 diff --git a/src/main/java/blockchain/client/CAClientWrapper.java b/src/main/java/blockchain/client/CAClientWrapper.java index 15e5b71..5df0efb 100644 --- a/src/main/java/blockchain/client/CAClientWrapper.java +++ b/src/main/java/blockchain/client/CAClientWrapper.java @@ -1,7 +1,10 @@ package blockchain.client; import blockchain.user.UserContext; -import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi; +import blockchain.utility.Util; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.hyperledger.fabric.sdk.Enrollment; import org.hyperledger.fabric.sdk.exception.CryptoException; import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; import org.hyperledger.fabric.sdk.security.CryptoSuite; @@ -12,14 +15,15 @@ import java.net.MalformedURLException; import java.util.Properties; public class CAClientWrapper { + private static Logger logger = Logger.getLogger(CAClientWrapper.class); private String caUrl; private Properties properties; private HFCAClient hfcaClient; private UserContext adminContext; - public void setAdminContext(UserContext adminContext) { - this.adminContext = adminContext; - } + public void setAdminContext(UserContext adminContext) { this.adminContext = adminContext; } + + public UserContext getAdminContext(){ return adminContext; } public HFCAClient getHfcaClient(){ return hfcaClient; @@ -37,11 +41,28 @@ public class CAClientWrapper { hfcaClient.setCryptoSuite(cryptoSuite); } - //TODO - public UserContext enrollAdmin(String username, String password) throws Exception{ - UserContext userContext = new UserContext(); + public UserContext enrollAdmin(String username, String password, String affiliation) throws Exception{ + BasicConfigurator.configure(); + UserContext checkAdmin; + checkAdmin = Util.readUserContext(affiliation, username); - return null; + //SANITY CHECK + if(adminContext.getName().isEmpty()) throw new NullPointerException(); + + if(checkAdmin!=null){ + logger.warn("Admin already enrolled, skip"); + return checkAdmin; + } + + logger.info("Try hfcaClient.enroll"); + Enrollment enrollment = hfcaClient.enroll(username,password); + + logger.info("Admin enrolled"); + adminContext.setEnrollment(enrollment); + + logger.info("Write admin in msp directory"); + Util.writeUserContext(adminContext); + return adminContext; } diff --git a/src/main/java/blockchain/configuration/Config.java b/src/main/java/blockchain/configuration/Config.java new file mode 100644 index 0000000..0f0b9ee --- /dev/null +++ b/src/main/java/blockchain/configuration/Config.java @@ -0,0 +1,28 @@ +package blockchain.configuration; + +public class Config { + + public static final String ORG1_MSP = "Org1MSP"; + + public static final String ORG1 = "Org1"; + + public static final String ADMIN = "admin"; + + public static final String ADMIN_PASSWORD = "adminpw"; + + public static final String CA_ORG1_URL = "http://vps577432.ovh.net:7054"; + + public static final String ORDERER_URL = "http://vps577432.ovh.net:7050"; + + public static final String ORDERER_NAME = "orderer.example.com"; + + public static final String CHANNEL_NAME = "mychannel"; + + public static final String CHAINCODE_NAME = "mycc"; + + public static final String ORG1_PEER_0 = "peer0.org1.example.com"; + + public static final String ORG1_PEER_0_URL = "http://vps577432.ovh.net:7051"; + + +} diff --git a/src/main/java/blockchain/utility/Util.java b/src/main/java/blockchain/utility/Util.java index 6d29293..464c9b1 100644 --- a/src/main/java/blockchain/utility/Util.java +++ b/src/main/java/blockchain/utility/Util.java @@ -15,6 +15,8 @@ public class Util { ObjectOutputStream out = null; FileOutputStream fileOutputStream = null; try { + logger.info("Write user "+userContext.getName()+" of "+userContext.getAffiliation()); + String directoryPath = "msp/" + userContext.getAffiliation(); String filePath = directoryPath + "/" + userContext.getName() + ".context"; File directory = new File(directoryPath); diff --git a/src/test/java/blockchain/client/TestEnrollAdmin.java b/src/test/java/blockchain/client/TestEnrollAdmin.java new file mode 100644 index 0000000..3b27963 --- /dev/null +++ b/src/test/java/blockchain/client/TestEnrollAdmin.java @@ -0,0 +1,40 @@ +package blockchain.client; + +import blockchain.configuration.Config; +import blockchain.user.UserContext; +import org.hyperledger.fabric.sdk.Enrollment; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TestEnrollAdmin { + @Test + public void TestAEnrollAdmin(){ + String caUrl = Config.CA_ORG1_URL; + try { + CAClientWrapper caClientWrapper = new CAClientWrapper(caUrl,null); + + UserContext adminContext = new UserContext(); + adminContext.setName(Config.ADMIN); + adminContext.setAffiliation(Config.ORG1); + adminContext.setMspId(Config.ORG1_MSP); + + caClientWrapper.setAdminContext(adminContext); + + UserContext verifyUser = caClientWrapper.getAdminContext(); + assertEquals(Config.ADMIN, verifyUser.getName()); + assertEquals(Config.ORG1, verifyUser.getAffiliation()); + assertEquals(Config.ORG1_MSP, verifyUser.getMspId()); + + adminContext = caClientWrapper.enrollAdmin(adminContext.getName(),Config.ADMIN_PASSWORD,adminContext.getAffiliation()); + + //Check Admin Enrollement + Enrollment enrollment = adminContext.getEnrollment(); + System.out.println("admin cert : "+enrollment.getCert()); + System.out.println("admin keys : "+enrollment.getKey()); + }catch (Exception e){ + e.printStackTrace(); + } + + } +} diff --git a/target/classes/blockchain/client/CAClientWrapper.class b/target/classes/blockchain/client/CAClientWrapper.class index 6e94daae18a7925c0c2334b051b94f8f12aaab52..9edb4571625e5b6534dff9a3f0de8c162a354686 100644 GIT binary patch literal 3569 zcmb7G`FGS*6#ia2ZQ2kDP5~*43@TdMLIeuPB3f%J)oDfBf(xjxnangaO~y=yQulq| z_wA3sh0>$v=x_eu-{kT5y<|F*wlf6}CGX|EdvEUd-EIE<_qRU)^y9~NY{Mh!aYn}u zJgRn&smHj^$ApeaoYip-kE_QMI-bN+I?m&Qj;HaAj%Oh?OzG%|HLW(}blAwZp`g}j zrRB8Yq7t8JgR69BHF)aM*H9E_b^SuY4g|Wgeo!!FQCics$;1AOW;VJyA<$yU$-osz zXD`Z2(sZR)Fvr8d@d~`ui-BLXgV3={0$XB9J{QO$(J6llEB)Eky*H^@2g7>moKEo7M-3I78)U5Yq~kf^DS_VZ)d8y? zAVq>cblI|tq2qfc4bN!^G;kAYC~LT+VNSzkGNnulGVWth2qqcikvp0+S8>O{UyxOxNSHO>ykWSvuKPl%>*~ALRILna?|} zBNbwzXWm;g6-V^gt=TAB?_3MlP~^W7B%1Z(p|oa3Wid(=4f7hF=O<4xIpTom<9<1? z>|sac)}|H7vR@UKfjzjxz-_qQz(JfcunQRjyK$?5dvHp_iw0i7s~TQ2@H*Zw@Fw2U z@V0?>)aAPd-oyL+u7MBmp@xqPe2h;7ZmE^+SlM;Y_zsIHsD|6XPTV4}BLbh1ZeYvY zd?u#A&h=$VGfq*%rv^U5=K`B2g859Xn)kuhpmy?4=s3 z6hcDno*Pmd@h(Z%$qfXBvdX%I{;nFnG1jCtJ!*&3e$uhtnnYmdUD9UK96OvUfe9I~ z?Ii4NPXuFSlM?8x*{bSj_(9<48Zhd0f!l{=lmY@;b!Uut9-F%2S51`;I+o}g0*4wl z#I>4DcYV)RPaT1qEEYj%kJ)o0Q65;V*NKMRY2~>4U){Qc18W(${_eFJPCW`wsAhbt zLbq&w-!Ds!#mSg=3gtku%mmu4$}92QoQy9Aw(8E4TsgB;2S|)nfx(8@lb!i`eOO~0 z$D%g8i2rg*tI}xc`4!>{H%+LS*%p~G zVu6YofxB>^j&jpV<(+kv58@C%p%6%}&0ITsuAy0>NcHqxr61SOT7$EN1c9`qNLV{* z>EN7BlNJRp6RTI@bw&g#Fr8|A(|kYoX|&-mj^HTn#xc@%0w;OH$zE~eJgq1qcPv87 z_K<}X|F{WZQN5$$ONs%w7x$5+Mji+Z;QrVH zp=fBO)xsk5eZ7lVcU-w37GNx3{dZXRJ35}Yh7EsqrT#+4&)As0X#wf3)D^YuT)?Kt z%f1C{KHj2^w!}xGt7QQHyDCo2QIL;dJ@@XYdzc`O@Z=aN zJ5DE0;vv#CPC!o)(i9z6fKSCPSIIA6kO5KT7w`agiqZmxxND~E3m9hRrD$yr9>i$| zb%girX!-}cG(5B+;weS-hZ(IbjmJs8J2FVY^tMH8{{hlX))OzM9{ee2H78PnKkC)ptRR?aCWb^o@z`XmgdQb&4uX_TZ=7QCW?Ks49}Z{8=# zd&`mQj$Mn&HnV93MB0(cgXyLg` YJg;{rbZb>PqAIn!J zzVHM1p^T?x#`?y+IX%DU+&(?$-2VLa{Re;wj&oST!z>1K*6F-=+6@g) z81nU6FSdWzwlq8?fhuO(Z1-Z}8AIWZVAqd;+&xIQ@WSwAGj_)NMWwdNQ7)wQk_&NE+urmt7$*Ez?C)1N^wQ_u< z`}2{mM0i>)om4KV(-t@VU?2h!=;AXUPduT!{+MB9{Dr1fN_ey~%3X%7i4Z|a_o2@;xGk`xH}n F@Ef}WucZJ0 literal 0 HcmV?d00001 diff --git a/target/classes/blockchain/utility/Util.class b/target/classes/blockchain/utility/Util.class index 5f9ec2d126444dcb2fb7300f176f0c1fdf3daaf1..3a430d4b0a4d8f4571e48c32433aecc28355685e 100644 GIT binary patch literal 3819 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